?????????? ????????? - ??????????????? - /home/agenciai/public_html/cd38d8/polygon.tar
???????
polygon_45_set_concept.hpp 0000644 00000045701 15125572616 0011663 0 ustar 00 /* 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_45_SET_CONCEPT_HPP #define BOOST_POLYGON_POLYGON_45_SET_CONCEPT_HPP #include "polygon_45_set_data.hpp" #include "polygon_45_set_traits.hpp" #include "detail/polygon_45_touch.hpp" namespace boost { namespace polygon{ template <typename T, typename T2> struct is_either_polygon_45_set_type { typedef typename gtl_or<typename is_polygon_45_set_type<T>::type, typename is_polygon_45_set_type<T2>::type >::type type; }; template <typename T> struct is_polygon_45_or_90_set_type { typedef typename gtl_or<typename is_polygon_45_set_type<T>::type, typename is_polygon_90_set_type<T>::type >::type type; }; template <typename polygon_set_type> typename enable_if< typename gtl_if<typename is_polygon_45_or_90_set_type<polygon_set_type>::type>::type, typename polygon_45_set_traits<polygon_set_type>::iterator_type>::type begin_45_set_data(const polygon_set_type& polygon_set) { return polygon_45_set_traits<polygon_set_type>::begin(polygon_set); } template <typename polygon_set_type> typename enable_if< typename gtl_if<typename is_polygon_45_or_90_set_type<polygon_set_type>::type>::type, typename polygon_45_set_traits<polygon_set_type>::iterator_type>::type end_45_set_data(const polygon_set_type& polygon_set) { return polygon_45_set_traits<polygon_set_type>::end(polygon_set); } template <typename polygon_set_type> typename enable_if< typename gtl_if<typename is_polygon_45_set_type<polygon_set_type>::type>::type, bool>::type clean(const polygon_set_type& polygon_set) { return polygon_45_set_traits<polygon_set_type>::clean(polygon_set); } //assign template <typename polygon_set_type_1, typename polygon_set_type_2> typename enable_if< typename gtl_and< typename gtl_if<typename is_mutable_polygon_45_set_type<polygon_set_type_1>::type>::type, typename gtl_if<typename is_polygon_45_or_90_set_type<polygon_set_type_2>::type>::type>::type, polygon_set_type_1>::type & assign(polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { polygon_45_set_mutable_traits<polygon_set_type_1>::set(lvalue, begin_45_set_data(rvalue), end_45_set_data(rvalue)); return lvalue; } //get trapezoids template <typename output_container_type, typename polygon_set_type> typename enable_if< typename gtl_if<typename is_polygon_45_set_type<polygon_set_type>::type>::type, void>::type get_trapezoids(output_container_type& output, const polygon_set_type& polygon_set) { clean(polygon_set); polygon_45_set_data<typename polygon_45_set_traits<polygon_set_type>::coordinate_type> ps; assign(ps, polygon_set); ps.get_trapezoids(output); } //get trapezoids template <typename output_container_type, typename polygon_set_type> typename enable_if< typename gtl_if<typename is_polygon_45_set_type<polygon_set_type>::type>::type, void>::type get_trapezoids(output_container_type& output, const polygon_set_type& polygon_set, orientation_2d slicing_orientation) { clean(polygon_set); polygon_45_set_data<typename polygon_45_set_traits<polygon_set_type>::coordinate_type> ps; assign(ps, polygon_set); ps.get_trapezoids(output, slicing_orientation); } //equivalence template <typename polygon_set_type_1, typename polygon_set_type_2> typename enable_if< typename gtl_and_3<typename gtl_if<typename is_polygon_45_or_90_set_type<polygon_set_type_1>::type>::type, typename gtl_if<typename is_polygon_45_or_90_set_type<polygon_set_type_2>::type>::type, typename gtl_if<typename is_either_polygon_45_set_type<polygon_set_type_1, polygon_set_type_2>::type>::type>::type, bool>::type equivalence(const polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { polygon_45_set_data<typename polygon_45_set_traits<polygon_set_type_1>::coordinate_type> ps1; assign(ps1, lvalue); polygon_45_set_data<typename polygon_45_set_traits<polygon_set_type_2>::coordinate_type> ps2; assign(ps2, rvalue); return ps1 == ps2; } //clear template <typename polygon_set_type> typename enable_if< typename gtl_if<typename is_mutable_polygon_45_set_type<polygon_set_type>::type>::type, void>::type clear(polygon_set_type& polygon_set) { polygon_45_set_data<typename polygon_45_set_traits<polygon_set_type>::coordinate_type> ps; assign(polygon_set, ps); } //empty template <typename polygon_set_type> typename enable_if< typename gtl_if<typename is_mutable_polygon_45_set_type<polygon_set_type>::type>::type, bool>::type empty(const polygon_set_type& polygon_set) { if(clean(polygon_set)) return begin_45_set_data(polygon_set) == end_45_set_data(polygon_set); polygon_45_set_data<typename polygon_45_set_traits<polygon_set_type>::coordinate_type> ps; assign(ps, polygon_set); ps.clean(); return ps.empty(); } //extents template <typename polygon_set_type, typename rectangle_type> typename enable_if< typename gtl_and< typename gtl_if<typename is_mutable_polygon_45_set_type<polygon_set_type>::type>::type, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, bool>::type extents(rectangle_type& extents_rectangle, const polygon_set_type& polygon_set) { clean(polygon_set); polygon_45_set_data<typename polygon_45_set_traits<polygon_set_type>::coordinate_type> ps; assign(ps, polygon_set); return ps.extents(extents_rectangle); } //area template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::area_type>::type area(const polygon_set_type& polygon_set) { typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; typedef polygon_45_with_holes_data<Unit> p_type; typedef typename coordinate_traits<Unit>::area_type area_type; std::vector<p_type> polys; assign(polys, polygon_set); area_type retval = (area_type)0; for(std::size_t i = 0; i < polys.size(); ++i) { retval += area(polys[i]); } return retval; } //interact template <typename polygon_set_type_1, typename polygon_set_type_2> typename enable_if < typename gtl_and< typename gtl_if<typename is_mutable_polygon_45_set_type<polygon_set_type_1>::type>::type, typename gtl_if<typename is_polygon_45_or_90_set_type<polygon_set_type_2>::type>::type >::type, polygon_set_type_1>::type& interact(polygon_set_type_1& polygon_set_1, const polygon_set_type_2& polygon_set_2) { typedef typename polygon_45_set_traits<polygon_set_type_1>::coordinate_type Unit; std::vector<polygon_45_data<Unit> > polys; assign(polys, polygon_set_1); std::vector<std::set<int> > graph(polys.size()+1, std::set<int>()); connectivity_extraction_45<Unit> ce; ce.insert(polygon_set_2); for(std::size_t i = 0; i < polys.size(); ++i){ ce.insert(polys[i]); } ce.extract(graph); clear(polygon_set_1); polygon_45_set_data<Unit> ps; for(std::set<int>::iterator itr = graph[0].begin(); itr != graph[0].end(); ++itr){ ps.insert(polys[(*itr)-1]); } assign(polygon_set_1, ps); return polygon_set_1; } // //self_intersect // template <typename polygon_set_type> // typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type>::type, // polygon_set_type>::type & // self_intersect(polygon_set_type& polygon_set) { // typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; // //TODO // } template <typename polygon_set_type, typename coord_type> typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, polygon_set_type>::type & resize(polygon_set_type& polygon_set, coord_type resizing, RoundingOption rounding = CLOSEST, CornerOption corner = INTERSECTION) { typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; clean(polygon_set); polygon_45_set_data<Unit> ps; assign(ps, polygon_set); ps.resize(resizing, rounding, corner); assign(polygon_set, ps); return polygon_set; } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, polygon_set_type>::type & bloat(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { return resize(polygon_set, static_cast<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>(bloating)); } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, polygon_set_type>::type & shrink(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type shrinking) { return resize(polygon_set, -(typename polygon_45_set_traits<polygon_set_type>::coordinate_type)shrinking); } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, polygon_set_type>::type & grow_and(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; std::vector<polygon_45_data<Unit> > polys; assign(polys, polygon_set); clear(polygon_set); polygon_45_set_data<Unit> ps; for(std::size_t i = 0; i < polys.size(); ++i) { polygon_45_set_data<Unit> tmpPs; tmpPs.insert(polys[i]); bloat(tmpPs, bloating); tmpPs.clean(); //apply implicit OR on tmp polygon set ps.insert(tmpPs); } ps.self_intersect(); assign(polygon_set, ps); return polygon_set; } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, polygon_set_type>::type & scale_up(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type factor) { typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; clean(polygon_set); polygon_45_set_data<Unit> ps; assign(ps, polygon_set); ps.scale_up(factor); assign(polygon_set, ps); return polygon_set; } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, polygon_set_type>::type & scale_down(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type factor) { typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; clean(polygon_set); polygon_45_set_data<Unit> ps; assign(ps, polygon_set); ps.scale_down(factor); assign(polygon_set, ps); return polygon_set; } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, polygon_set_type>::type & scale(polygon_set_type& polygon_set, double factor) { typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; clean(polygon_set); polygon_45_set_data<Unit> ps; assign(ps, polygon_set); ps.scale(factor); assign(polygon_set, ps); return polygon_set; } //self_intersect template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, polygon_set_type>::type & self_intersect(polygon_set_type& polygon_set) { typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; polygon_45_set_data<Unit> ps; assign(ps, polygon_set); ps.self_intersect(); assign(polygon_set, ps); return polygon_set; } //self_xor template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, polygon_set_type>::type & self_xor(polygon_set_type& polygon_set) { typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; polygon_45_set_data<Unit> ps; assign(ps, polygon_set); ps.self_xor(); assign(polygon_set, ps); return polygon_set; } //transform template <typename polygon_set_type, typename transformation_type> typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, polygon_set_type>::type & transform(polygon_set_type& polygon_set, const transformation_type& transformation) { typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; clean(polygon_set); polygon_45_set_data<Unit> ps; assign(ps, polygon_set); ps.transform(transformation); assign(polygon_set, ps); return polygon_set; } //keep template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, polygon_set_type>::type & keep(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::area_type min_area, typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::area_type max_area, typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type min_width, typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type max_width, typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type min_height, typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type max_height) { typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; typedef typename coordinate_traits<Unit>::unsigned_area_type uat; std::list<polygon_45_data<Unit> > polys; assign(polys, polygon_set); typename std::list<polygon_45_data<Unit> >::iterator itr_nxt; for(typename std::list<polygon_45_data<Unit> >::iterator itr = polys.begin(); itr != polys.end(); itr = itr_nxt){ itr_nxt = itr; ++itr_nxt; rectangle_data<Unit> bbox; extents(bbox, *itr); uat pwidth = delta(bbox, HORIZONTAL); if(pwidth > min_width && pwidth <= max_width){ uat pheight = delta(bbox, VERTICAL); if(pheight > min_height && pheight <= max_height){ typename coordinate_traits<Unit>::area_type parea = area(*itr); if(parea <= max_area && parea >= min_area) { continue; } } } polys.erase(itr); } assign(polygon_set, polys); return polygon_set; } template <typename T> struct view_of<polygon_90_set_concept, T> { typedef typename get_coordinate_type<T, typename geometry_concept<T>::type >::type coordinate_type; T* tp; std::vector<polygon_90_with_holes_data<coordinate_type> > polys; view_of(T& obj) : tp(&obj), polys() { std::vector<polygon_with_holes_data<coordinate_type> > gpolys; assign(gpolys, obj); for(typename std::vector<polygon_with_holes_data<coordinate_type> >::iterator itr = gpolys.begin(); itr != gpolys.end(); ++itr) { polys.push_back(polygon_90_with_holes_data<coordinate_type>()); assign(polys.back(), view_as<polygon_90_with_holes_concept>(*itr)); } } view_of(const T& obj) : tp(), polys() { std::vector<polygon_with_holes_data<coordinate_type> > gpolys; assign(gpolys, obj); for(typename std::vector<polygon_with_holes_data<coordinate_type> >::iterator itr = gpolys.begin(); itr != gpolys.end(); ++itr) { polys.push_back(polygon_90_with_holes_data<coordinate_type>()); assign(polys.back(), view_as<polygon_90_with_holes_concept>(*itr)); } } typedef typename std::vector<polygon_90_with_holes_data<coordinate_type> >::const_iterator iterator_type; typedef view_of operator_arg_type; inline iterator_type begin() const { return polys.begin(); } inline iterator_type end() const { return polys.end(); } inline orientation_2d orient() const { return HORIZONTAL; } inline bool clean() const { return false; } inline bool sorted() const { return false; } inline T& get() { return *tp; } }; template <typename T> struct polygon_90_set_traits<view_of<polygon_90_set_concept, T> > { typedef typename view_of<polygon_90_set_concept, T>::coordinate_type coordinate_type; typedef typename view_of<polygon_90_set_concept, T>::iterator_type iterator_type; typedef view_of<polygon_90_set_concept, T> operator_arg_type; static inline iterator_type begin(const view_of<polygon_90_set_concept, T>& polygon_set) { return polygon_set.begin(); } static inline iterator_type end(const view_of<polygon_90_set_concept, T>& polygon_set) { return polygon_set.end(); } static inline orientation_2d orient(const view_of<polygon_90_set_concept, T>& polygon_set) { return polygon_set.orient(); } static inline bool clean(const view_of<polygon_90_set_concept, T>& polygon_set) { return polygon_set.clean(); } static inline bool sorted(const view_of<polygon_90_set_concept, T>& polygon_set) { return polygon_set.sorted(); } }; template <typename T> struct geometry_concept<view_of<polygon_90_set_concept, T> > { typedef polygon_90_set_concept type; }; template <typename T> struct get_coordinate_type<view_of<polygon_90_set_concept, T>, polygon_90_set_concept> { typedef typename view_of<polygon_90_set_concept, T>::coordinate_type type; }; template <typename T> struct get_iterator_type_2<view_of<polygon_90_set_concept, T>, polygon_90_set_concept> { typedef typename view_of<polygon_90_set_concept, T>::iterator_type type; static type begin(const view_of<polygon_90_set_concept, T>& t) { return t.begin(); } static type end(const view_of<polygon_90_set_concept, T>& t) { return t.end(); } }; } } #include "detail/polygon_45_set_view.hpp" #endif polygon_90_set_traits.hpp 0000644 00000040103 15125572616 0011525 0 ustar 00 /* 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_TRAITS_HPP #define BOOST_POLYGON_POLYGON_90_SET_TRAITS_HPP namespace boost { namespace polygon{ struct polygon_90_set_concept {}; template <typename T, typename T2> struct traits_by_concept {}; template <typename T> struct traits_by_concept<T, coordinate_concept> { typedef coordinate_traits<T> type; }; template <typename T> struct traits_by_concept<T, interval_concept> { typedef interval_traits<T> type; }; template <typename T> struct traits_by_concept<T, point_concept> { typedef point_traits<T> type; }; template <typename T> struct traits_by_concept<T, rectangle_concept> { typedef rectangle_traits<T> type; }; template <typename T> struct traits_by_concept<T, segment_concept> { typedef segment_traits<T> type; }; template <typename T> struct traits_by_concept<T, polygon_90_concept> { typedef polygon_traits<T> type; }; template <typename T> struct traits_by_concept<T, polygon_90_with_holes_concept> { typedef polygon_traits<T> type; }; template <typename T> struct traits_by_concept<T, polygon_45_concept> { typedef polygon_traits<T> type; }; template <typename T> struct traits_by_concept<T, polygon_45_with_holes_concept> { typedef polygon_traits<T> type; }; template <typename T> struct traits_by_concept<T, polygon_concept> { typedef polygon_traits<T> type; }; template <typename T> struct traits_by_concept<T, polygon_with_holes_concept> { typedef polygon_traits<T> type; }; struct polygon_45_set_concept; struct polygon_set_concept; template <typename T> struct polygon_90_set_traits; template <typename T> struct polygon_45_set_traits; template <typename T> struct polygon_set_traits; template <typename T> struct traits_by_concept<T, polygon_90_set_concept> { typedef polygon_90_set_traits<T> type; }; template <typename T> struct traits_by_concept<T, polygon_45_set_concept> { typedef polygon_45_set_traits<T> type; }; template <typename T> struct traits_by_concept<T, polygon_set_concept> { typedef polygon_set_traits<T> type; }; template <typename T, typename T2> struct get_coordinate_type { typedef typename traits_by_concept<T, T2>::type traits_type; typedef typename traits_type::coordinate_type type; }; //want to prevent recursive template definition syntax errors, so duplicate get_coordinate_type template <typename T, typename T2> struct get_coordinate_type_2 { typedef typename traits_by_concept<T, T2>::type traits_type; typedef typename traits_type::coordinate_type type; }; template <typename T> struct get_coordinate_type<T, undefined_concept> { typedef typename get_coordinate_type_2<typename std::iterator_traits <typename T::iterator>::value_type, typename geometry_concept<typename std::iterator_traits <typename T::iterator>::value_type>::type>::type type; }; template <typename T, typename T2> struct get_iterator_type_2 { typedef const T* type; static type begin(const T& t) { return &t; } static type end(const T& t) { const T* tp = &t; ++tp; return tp; } }; template <typename T> struct get_iterator_type { typedef get_iterator_type_2<T, typename geometry_concept<T>::type> indirect_type; typedef typename indirect_type::type type; static type begin(const T& t) { return indirect_type::begin(t); } static type end(const T& t) { return indirect_type::end(t); } }; template <typename T> struct get_iterator_type_2<T, undefined_concept> { typedef typename T::const_iterator type; static type begin(const T& t) { return t.begin(); } static type end(const T& t) { return t.end(); } }; // //helpers for allowing polygon 45 and containers of polygon 45 to behave interchangably in polygon_45_set_traits // template <typename T, typename T2> // struct get_coordinate_type_45 {}; // template <typename T, typename T2> // struct get_coordinate_type_2_45 {}; // template <typename T> // struct get_coordinate_type_45<T, void> { // typedef typename get_coordinate_type_2_45< typename T::value_type, typename geometry_concept<typename T::value_type>::type >::type type; }; // template <typename T> // struct get_coordinate_type_45<T, polygon_45_concept> { typedef typename polygon_traits<T>::coordinate_type type; }; // template <typename T> // struct get_coordinate_type_45<T, polygon_45_with_holes_concept> { typedef typename polygon_traits<T>::coordinate_type type; }; // template <typename T> // struct get_coordinate_type_2_45<T, polygon_45_concept> { typedef typename polygon_traits<T>::coordinate_type type; }; // template <typename T> // struct get_coordinate_type_2_45<T, polygon_45_with_holes_concept> { typedef typename polygon_traits<T>::coordinate_type type; }; // template <typename T, typename T2> // struct get_iterator_type_45 {}; // template <typename T> // struct get_iterator_type_45<T, void> { // typedef typename T::const_iterator type; // static type begin(const T& t) { return t.begin(); } // static type end(const T& t) { return t.end(); } // }; // template <typename T> // struct get_iterator_type_45<T, polygon_45_concept> { // typedef const T* type; // static type begin(const T& t) { return &t; } // static type end(const T& t) { const T* tp = &t; ++tp; return tp; } // }; // template <typename T> // struct get_iterator_type_45<T, polygon_45_with_holes_concept> { // typedef const T* type; // static type begin(const T& t) { return &t; } // static type end(const T& t) { const T* tp = &t; ++tp; return tp; } // }; // template <typename T> // struct get_iterator_type_45<T, polygon_90_set_concept> { // typedef const T* type; // static type begin(const T& t) { return &t; } // static type end(const T& t) { const T* tp = &t; ++tp; return tp; } // }; template <typename T> struct polygon_90_set_traits { typedef typename get_coordinate_type<T, typename geometry_concept<T>::type >::type coordinate_type; typedef get_iterator_type<T> indirection_type; typedef typename get_iterator_type<T>::type iterator_type; typedef T operator_arg_type; static inline iterator_type begin(const T& polygon_set) { return indirection_type::begin(polygon_set); } static inline iterator_type end(const T& polygon_set) { return indirection_type::end(polygon_set); } static inline orientation_2d orient(const T&) { return HORIZONTAL; } static inline bool clean(const T&) { return false; } static inline bool sorted(const T&) { return false; } }; template <typename T> struct is_manhattan_polygonal_concept { typedef gtl_no type; }; template <> struct is_manhattan_polygonal_concept<rectangle_concept> { typedef gtl_yes type; }; template <> struct is_manhattan_polygonal_concept<polygon_90_concept> { typedef gtl_yes type; }; template <> struct is_manhattan_polygonal_concept<polygon_90_with_holes_concept> { typedef gtl_yes type; }; template <> struct is_manhattan_polygonal_concept<polygon_90_set_concept> { typedef gtl_yes type; }; template <typename T> struct is_polygon_90_set_type { typedef typename is_manhattan_polygonal_concept<typename geometry_concept<T>::type>::type type; }; template <typename T> struct is_polygon_90_set_type<std::list<T> > { typedef typename gtl_or< typename is_manhattan_polygonal_concept<typename geometry_concept<std::list<T> >::type>::type, typename is_manhattan_polygonal_concept<typename geometry_concept<typename std::list<T>::value_type>::type>::type>::type type; }; template <typename T> struct is_polygon_90_set_type<std::vector<T> > { typedef typename gtl_or< typename is_manhattan_polygonal_concept<typename geometry_concept<std::vector<T> >::type>::type, typename is_manhattan_polygonal_concept<typename geometry_concept<typename std::vector<T>::value_type>::type>::type>::type type; }; template <typename T> struct is_mutable_polygon_90_set_type { typedef typename gtl_same_type<polygon_90_set_concept, typename geometry_concept<T>::type>::type type; }; template <typename T> struct is_mutable_polygon_90_set_type<std::list<T> > { typedef typename gtl_or< typename gtl_same_type<polygon_90_set_concept, typename geometry_concept<std::list<T> >::type>::type, typename is_manhattan_polygonal_concept<typename geometry_concept<typename std::list<T>::value_type>::type>::type>::type type; }; template <typename T> struct is_mutable_polygon_90_set_type<std::vector<T> > { typedef typename gtl_or< typename gtl_same_type<polygon_90_set_concept, typename geometry_concept<std::vector<T> >::type>::type, typename is_manhattan_polygonal_concept<typename geometry_concept<typename std::vector<T>::value_type>::type>::type>::type type; }; // //specialization for rectangle, polygon_90 and polygon_90_with_holes types // template <typename T> // struct polygon_90_set_traits // typedef typename geometry_concept<T>::type concept_type; // typedef typename get_coordinate_type<T, concept_type>::type coordinate_type; // typedef iterator_geometry_to_set<concept_type, T> iterator_type; // typedef T operator_arg_type; // static inline iterator_type begin(const T& polygon_set) { // return iterator_geometry_to_set<concept_type, T>(polygon_set, LOW, HORIZONTAL); // } // static inline iterator_type end(const T& polygon_set) { // return iterator_geometry_to_set<concept_type, T>(polygon_set, HIGH, HORIZONTAL); // } // static inline orientation_2d orient(const T& polygon_set) { return HORIZONTAL; } // static inline bool clean(const T& polygon_set) { return false; } // static inline bool sorted(const T& polygon_set) { return false; } // }; // //specialization for containers of recangle, polygon_90, polygon_90_with_holes // template <typename T> // struct polygon_90_set_traits<T, typename is_manhattan_polygonal_concept<typename std::iterator_traits<typename T::iterator>::value_type>::type> { // typedef typename std::iterator_traits<typename T::iterator>::value_type geometry_type; // typedef typename geometry_concept<geometry_type>::type concept_type; // typedef typename get_coordinate_type<geometry_type, concept_type>::type coordinate_type; // typedef iterator_geometry_range_to_set<concept_type, typename T::const_iterator> iterator_type; // typedef T operator_arg_type; // static inline iterator_type begin(const T& polygon_set) { // return iterator_type(polygon_set.begin(), HORIZONTAL); // } // static inline iterator_type end(const T& polygon_set) { // return iterator_type(polygon_set.end(), HORIZONTAL); // } // static inline orientation_2d orient(const T& polygon_set) { return HORIZONTAL; } // static inline bool clean(const T& polygon_set) { return false; } // static inline bool sorted(const T& polygon_set) { return false; } // }; //get dispatch functions template <typename output_container_type, typename pst> void get_90_dispatch(output_container_type& output, const pst& ps, orientation_2d orient, rectangle_concept ) { form_rectangles(output, ps.begin(), ps.end(), orient, rectangle_concept()); } template <typename output_container_type, typename pst> void get_90_dispatch(output_container_type& output, const pst& ps, orientation_2d orient, polygon_90_concept tag) { get_polygons(output, ps.begin(), ps.end(), orient, true, tag); } template <typename output_container_type, typename pst> void get_90_dispatch(output_container_type& output, const pst& ps, orientation_2d orient, polygon_90_with_holes_concept tag) { get_polygons(output, ps.begin(), ps.end(), orient, false, tag); } //by default works with containers of rectangle, polygon or polygon with holes //must be specialized to work with anything else template <typename T> struct polygon_90_set_mutable_traits {}; template <typename T> struct polygon_90_set_mutable_traits<std::list<T> > { typedef typename geometry_concept<T>::type concept_type; template <typename input_iterator_type> static inline void set(std::list<T>& polygon_set, input_iterator_type input_begin, input_iterator_type input_end, orientation_2d orient) { polygon_set.clear(); polygon_90_set_data<typename polygon_90_set_traits<std::list<T> >::coordinate_type> ps(orient); ps.reserve(std::distance(input_begin, input_end)); ps.insert(input_begin, input_end, orient); ps.clean(); get_90_dispatch(polygon_set, ps, orient, concept_type()); } }; template <typename T> struct polygon_90_set_mutable_traits<std::vector<T> > { typedef typename geometry_concept<T>::type concept_type; template <typename input_iterator_type> static inline void set(std::vector<T>& polygon_set, input_iterator_type input_begin, input_iterator_type input_end, orientation_2d orient) { polygon_set.clear(); size_t num_ele = std::distance(input_begin, input_end); polygon_set.reserve(num_ele); polygon_90_set_data<typename polygon_90_set_traits<std::list<T> >::coordinate_type> ps(orient); ps.reserve(num_ele); ps.insert(input_begin, input_end, orient); ps.clean(); get_90_dispatch(polygon_set, ps, orient, concept_type()); } }; template <typename T> struct polygon_90_set_mutable_traits<polygon_90_set_data<T> > { template <typename input_iterator_type> static inline void set(polygon_90_set_data<T>& polygon_set, input_iterator_type input_begin, input_iterator_type input_end, orientation_2d orient) { polygon_set.clear(); polygon_set.reserve(std::distance(input_begin, input_end)); polygon_set.insert(input_begin, input_end, orient); } }; template <typename T> struct polygon_90_set_traits<polygon_90_set_data<T> > { typedef typename polygon_90_set_data<T>::coordinate_type coordinate_type; typedef typename polygon_90_set_data<T>::iterator_type iterator_type; typedef typename polygon_90_set_data<T>::operator_arg_type operator_arg_type; static inline iterator_type begin(const polygon_90_set_data<T>& polygon_set) { return polygon_set.begin(); } static inline iterator_type end(const polygon_90_set_data<T>& polygon_set) { return polygon_set.end(); } static inline orientation_2d orient(const polygon_90_set_data<T>& polygon_set) { return polygon_set.orient(); } static inline bool clean(const polygon_90_set_data<T>& polygon_set) { polygon_set.clean(); return true; } static inline bool sorted(const polygon_90_set_data<T>& polygon_set) { polygon_set.sort(); return true; } }; template <typename T> struct is_polygon_90_set_concept { }; template <> struct is_polygon_90_set_concept<polygon_90_set_concept> { typedef gtl_yes type; }; template <> struct is_polygon_90_set_concept<rectangle_concept> { typedef gtl_yes type; }; template <> struct is_polygon_90_set_concept<polygon_90_concept> { typedef gtl_yes type; }; template <> struct is_polygon_90_set_concept<polygon_90_with_holes_concept> { typedef gtl_yes type; }; template <typename T> struct is_mutable_polygon_90_set_concept { typedef gtl_no type; }; template <> struct is_mutable_polygon_90_set_concept<polygon_90_set_concept> { typedef gtl_yes type; }; template <typename T> struct geometry_concept<polygon_90_set_data<T> > { typedef polygon_90_set_concept type; }; //template <typename T> //typename enable_if<typename is_polygon_90_set_type<T>::type, void>::type //print_is_polygon_90_set_concept(const T& t) { std::cout << "is polygon 90 set concept\n"; } //template <typename T> //typename enable_if<typename is_mutable_polygon_90_set_type<T>::type, void>::type //print_is_mutable_polygon_90_set_concept(const T& t) { std::cout << "is mutable polygon 90 set concept\n"; } } } #endif segment_concept.hpp 0000644 00000047166 15125572616 0010462 0 ustar 00 // Boost.Polygon library segment_concept.hpp header file // Copyright (c) Intel Corporation 2008. // Copyright (c) 2008-2012 Simonson Lucanus. // Copyright (c) 2012-2012 Andrii Sydorchuk. // See http://www.boost.org for updates, documentation, and revision history. // Use, modification and distribution is 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_SEGMENT_CONCEPT_HPP #define BOOST_POLYGON_SEGMENT_CONCEPT_HPP #include "isotropy.hpp" #include "segment_traits.hpp" #include "rectangle_concept.hpp" namespace boost { namespace polygon { struct segment_concept {}; template <typename ConceptType> struct is_segment_concept { typedef gtl_no type; }; template <> struct is_segment_concept<segment_concept> { typedef gtl_yes type; }; template <typename ConceptType> struct is_mutable_segment_concept { typedef gtl_no type; }; template <> struct is_mutable_segment_concept<segment_concept> { typedef gtl_yes type; }; template <typename GeometryType, typename BoolType> struct segment_distance_type_by_concept { typedef void type; }; template <typename GeometryType> struct segment_distance_type_by_concept<GeometryType, gtl_yes> { typedef typename coordinate_traits< typename segment_traits<GeometryType>::coordinate_type >::coordinate_distance type; }; template <typename GeometryType> struct segment_distance_type { typedef typename segment_distance_type_by_concept< GeometryType, typename is_segment_concept< typename geometry_concept<GeometryType>::type >::type >::type type; }; template <typename GeometryType, typename BoolType> struct segment_point_type_by_concept { typedef void type; }; template <typename GeometryType> struct segment_point_type_by_concept<GeometryType, gtl_yes> { typedef typename segment_traits<GeometryType>::point_type type; }; template <typename GeometryType> struct segment_point_type { typedef typename segment_point_type_by_concept< GeometryType, typename is_segment_concept< typename geometry_concept<GeometryType>::type >::type >::type type; }; template <typename GeometryType, typename BoolType> struct segment_coordinate_type_by_concept { typedef void type; }; template <typename GeometryType> struct segment_coordinate_type_by_concept<GeometryType, gtl_yes> { typedef typename segment_traits<GeometryType>::coordinate_type type; }; template <typename GeometryType> struct segment_coordinate_type { typedef typename segment_coordinate_type_by_concept< GeometryType, typename is_segment_concept< typename geometry_concept<GeometryType>::type >::type >::type type; }; struct y_s_get : gtl_yes {}; template <typename Segment> typename enable_if< typename gtl_and< y_s_get, typename is_segment_concept< typename geometry_concept<Segment>::type >::type >::type, typename segment_point_type<Segment>::type>::type get(const Segment& segment, direction_1d dir) { return segment_traits<Segment>::get(segment, dir); } struct y_s_set : gtl_yes {}; template <typename Segment, typename Point> typename enable_if< typename gtl_and_3< y_s_set, typename is_mutable_segment_concept< typename geometry_concept<Segment>::type >::type, typename is_point_concept< typename geometry_concept<Point>::type >::type >::type, void>::type set(Segment& segment, direction_1d dir, const Point& point) { segment_mutable_traits<Segment>::set(segment, dir, point); } struct y_s_construct : gtl_yes {}; template <typename Segment, typename Point1, typename Point2> typename enable_if< typename gtl_and_4< y_s_construct, typename is_mutable_segment_concept< typename geometry_concept<Segment>::type >::type, typename is_point_concept< typename geometry_concept<Point1>::type >::type, typename is_point_concept< typename geometry_concept<Point2>::type >::type >::type, Segment>::type construct(const Point1& low, const Point2& high) { return segment_mutable_traits<Segment>::construct(low, high); } struct y_s_copy_construct : gtl_yes {}; template <typename Segment1, typename Segment2> typename enable_if< typename gtl_and_3< y_s_copy_construct, typename is_mutable_segment_concept< typename geometry_concept<Segment1>::type >::type, typename is_segment_concept< typename geometry_concept<Segment2>::type >::type >::type, Segment1>::type copy_construct(const Segment2& segment) { return construct<Segment1>(get(segment, LOW), get(segment, HIGH)); } struct y_s_assign : gtl_yes {}; template <typename Segment1, typename Segment2> typename enable_if< typename gtl_and_3< y_s_assign, typename is_mutable_segment_concept< typename geometry_concept<Segment1>::type >::type, typename is_segment_concept< typename geometry_concept<Segment2>::type >::type >::type, Segment1>::type& assign(Segment1& segment1, const Segment2& segment2) { return segment1 = copy_construct<Segment1>(segment2); } struct y_s_equivalence : gtl_yes {}; template <typename Segment1, typename Segment2> typename enable_if< typename gtl_and_3< y_s_equivalence, typename is_segment_concept< typename geometry_concept<Segment1>::type >::type, typename is_segment_concept< typename geometry_concept<Segment2>::type >::type >::type, bool>::type equivalence(const Segment1& segment1, const Segment2& segment2) { return get(segment1, LOW) == get(segment2, LOW) && get(segment1, HIGH) == get(segment2, HIGH); } struct y_s_low : gtl_yes {}; template <typename Segment> typename enable_if< typename gtl_and< y_s_low, typename is_segment_concept< typename geometry_concept<Segment>::type >::type >::type, typename segment_point_type<Segment>::type>::type low(const Segment& segment) { return get(segment, LOW); } struct y_s_high : gtl_yes {}; template <typename Segment> typename enable_if< typename gtl_and< y_s_high, typename is_segment_concept< typename geometry_concept<Segment>::type >::type >::type, typename segment_point_type<Segment>::type>::type high(const Segment& segment) { return get(segment, HIGH); } struct y_s_center : gtl_yes {}; template <typename Segment> typename enable_if< typename gtl_and< y_s_center, typename is_segment_concept< typename geometry_concept<Segment>::type >::type >::type, typename segment_point_type<Segment>::type>::type center(const Segment& segment) { return construct<typename segment_point_type<Segment>::type>( (x(high(segment)) + x(low(segment)))/2, (y(high(segment)) + y(low(segment)))/2); } struct y_s_low2 : gtl_yes {}; template <typename Segment, typename Point> typename enable_if< typename gtl_and_3< y_s_low2, typename is_mutable_segment_concept< typename geometry_concept<Segment>::type >::type, typename is_point_concept< typename geometry_concept<Point>::type >::type >::type, void>::type low(Segment& segment, const Point& point) { set(segment, LOW, point); } struct y_s_high2 : gtl_yes {}; template <typename Segment, typename Point> typename enable_if< typename gtl_and_3< y_s_high2, typename is_mutable_segment_concept< typename geometry_concept<Segment>::type >::type, typename is_point_concept< typename geometry_concept<Point>::type >::type >::type, void>::type high(Segment& segment, const Point& point) { set(segment, HIGH, point); } struct y_s_orientation1 : gtl_yes {}; // -1 for CW, 0 for collinear and 1 for CCW. template <typename Segment1, typename Segment2> typename enable_if< typename gtl_and_3< y_s_orientation1, typename is_segment_concept< typename geometry_concept<Segment1>::type >::type, typename is_segment_concept< typename geometry_concept<Segment2>::type >::type >::type, int>::type orientation(const Segment1& segment1, const Segment2& segment2) { typedef typename coordinate_traits< typename segment_traits<Segment1>::coordinate_type >::manhattan_area_type int_x2; typedef typename coordinate_traits< typename segment_traits<Segment1>::coordinate_type >::unsigned_area_type uint_x2; int_x2 a1 = (int_x2)x(high(segment1)) - (int_x2)x(low(segment1)); int_x2 b1 = (int_x2)y(high(segment1)) - (int_x2)y(low(segment1)); int_x2 a2 = (int_x2)x(high(segment2)) - (int_x2)x(low(segment2)); int_x2 b2 = (int_x2)y(high(segment2)) - (int_x2)y(low(segment2)); int sign1 = 0; int sign2 = 0; if (a1 && b2) sign1 = ((a1 > 0) ^ (b2 > 0)) ? -1 : 1; if (a2 && b1) sign2 = ((a2 > 0) ^ (b1 > 0)) ? -1 : 1; if (sign1 != sign2) return (sign1 < sign2) ? -1 : 1; uint_x2 a3 = (uint_x2)(a1 < 0 ? -a1 : a1) * (uint_x2)(b2 < 0 ? -b2 : b2); uint_x2 b3 = (uint_x2)(b1 < 0 ? -b1 : b1) * (uint_x2)(a2 < 0 ? -a2 : a2); if (a3 == b3) return 0; return ((a3 < b3) ^ (sign1 == 1)) ? 1 : -1; } struct y_s_orientation2 : gtl_yes {}; // -1 for right, 0 for collinear and 1 for left. template <typename Segment, typename Point> typename enable_if< typename gtl_and_3< y_s_orientation2, typename is_segment_concept< typename geometry_concept<Segment>::type >::type, typename is_point_concept< typename geometry_concept<Point>::type >::type >::type, int>::type orientation(const Segment& segment, const Point& point) { Segment segment2 = construct<Segment>(high(segment), point); return orientation(segment, segment2); } struct y_s_contains : gtl_yes {}; template <typename Segment, typename Point> typename enable_if< typename gtl_and_3< y_s_contains, typename is_segment_concept< typename geometry_concept<Segment>::type >::type, typename is_point_concept< typename geometry_concept<Point>::type >::type >::type, bool>::type contains(const Segment& segment, const Point& point, bool consider_touch = true ) { if (orientation(segment, point)) return false; rectangle_data<typename segment_coordinate_type<Segment>::type> rect; set_points(rect, low(segment), high(segment)); if (!contains(rect, point, true)) return false; if (!consider_touch && (equivalence(low(segment), point) || equivalence(high(segment), point))) return false; return true; } struct y_s_contains2 : gtl_yes {}; template <typename Segment1, typename Segment2> typename enable_if< typename gtl_and_3< y_s_contains2, typename is_segment_concept< typename geometry_concept<Segment1>::type >::type, typename is_segment_concept< typename geometry_concept<Segment2>::type >::type >::type, bool>::type contains(const Segment1& segment1, const Segment2& segment2, bool consider_touch = true) { return contains(segment1, get(segment2, LOW), consider_touch) && contains(segment1, get(segment2, HIGH), consider_touch); } struct y_s_length : gtl_yes {}; template <typename Segment> typename enable_if< typename gtl_and< y_s_length, typename is_segment_concept< typename geometry_concept<Segment>::type >::type >::type, typename segment_distance_type<Segment>::type>::type length(const Segment& segment) { return euclidean_distance(low(segment), high(segment)); } struct y_s_scale_up : gtl_yes {}; template <typename Segment> typename enable_if< typename gtl_and< y_s_scale_up, typename is_mutable_segment_concept< typename geometry_concept<Segment>::type >::type >::type, Segment>::type& scale_up(Segment& segment, typename coordinate_traits< typename segment_coordinate_type<Segment>::type >::unsigned_area_type factor) { typename segment_point_type<Segment>::type l = low(segment); typename segment_point_type<Segment>::type h = high(segment); low(segment, scale_up(l, factor)); high(segment, scale_up(h, factor)); return segment; } struct y_s_scale_down : gtl_yes {}; template <typename Segment> typename enable_if< typename gtl_and< y_s_scale_down, typename is_mutable_segment_concept< typename geometry_concept<Segment>::type >::type >::type, Segment>::type& scale_down(Segment& segment, typename coordinate_traits< typename segment_coordinate_type<Segment>::type >::unsigned_area_type factor) { typename segment_point_type<Segment>::type l = low(segment); typename segment_point_type<Segment>::type h = high(segment); low(segment, scale_down(l, factor)); high(segment, scale_down(h, factor)); return segment; } struct y_s_scale : gtl_yes {}; template <typename Segment, typename Scale> typename enable_if< typename gtl_and< y_s_scale, typename is_mutable_segment_concept< typename geometry_concept<Segment>::type >::type >::type, Segment>::type& scale(Segment& segment, const Scale& sc) { typename segment_point_type<Segment>::type l = low(segment); typename segment_point_type<Segment>::type h = high(segment); low(segment, scale(l, sc)); high(segment, scale(h, sc)); return segment; } struct y_s_transform : gtl_yes {}; template <typename Segment, typename Transform> typename enable_if< typename gtl_and< y_s_transform, typename is_mutable_segment_concept< typename geometry_concept<Segment>::type >::type >::type, Segment>::type& transform(Segment& segment, const Transform& tr) { typename segment_point_type<Segment>::type l = low(segment); typename segment_point_type<Segment>::type h = high(segment); low(segment, transform(l, tr)); high(segment, transform(h, tr)); return segment; } struct y_s_move : gtl_yes {}; template <typename Segment> typename enable_if< typename gtl_and< y_s_move, typename is_mutable_segment_concept< typename geometry_concept<Segment>::type >::type >::type, Segment>::type& move(Segment& segment, orientation_2d orient, typename segment_coordinate_type<Segment>::type displacement) { typename segment_point_type<Segment>::type l = low(segment); typename segment_point_type<Segment>::type h = high(segment); low(segment, move(l, orient, displacement)); high(segment, move(h, orient, displacement)); return segment; } struct y_s_convolve : gtl_yes {}; template <typename Segment, typename Point> typename enable_if< typename gtl_and_3< y_s_convolve, typename is_mutable_segment_concept< typename geometry_concept<Segment>::type >::type, typename is_point_concept< typename geometry_concept<Point>::type >::type >::type, Segment>::type& convolve(Segment& segment, const Point& point) { typename segment_point_type<Segment>::type l = low(segment); typename segment_point_type<Segment>::type h = high(segment); low(segment, convolve(l, point)); high(segment, convolve(h, point)); return segment; } struct y_s_deconvolve : gtl_yes {}; template <typename Segment, typename Point> typename enable_if< typename gtl_and_3< y_s_deconvolve, typename is_mutable_segment_concept< typename geometry_concept<Segment>::type >::type, typename is_point_concept< typename geometry_concept<Point>::type >::type >::type, Segment>::type& deconvolve(Segment& segment, const Point& point) { typename segment_point_type<Segment>::type l = low(segment); typename segment_point_type<Segment>::type h = high(segment); low(segment, deconvolve(l, point)); high(segment, deconvolve(h, point)); return segment; } struct y_s_abuts1 : gtl_yes {}; template <typename Segment1, typename Segment2> typename enable_if< typename gtl_and_3< y_s_abuts1, typename is_segment_concept< typename geometry_concept<Segment1>::type >::type, typename is_segment_concept< typename geometry_concept<Segment2>::type >::type >::type, bool>::type abuts(const Segment1& segment1, const Segment2& segment2, direction_1d dir) { return dir.to_int() ? equivalence(low(segment2) , high(segment1)) : equivalence(low(segment1) , high(segment2)); } struct y_s_abuts2 : gtl_yes {}; template <typename Segment1, typename Segment2> typename enable_if< typename gtl_and_3< y_s_abuts2, typename is_segment_concept< typename geometry_concept<Segment1>::type >::type, typename is_segment_concept< typename geometry_concept<Segment2>::type >::type >::type, bool>::type abuts(const Segment1& segment1, const Segment2& segment2) { return abuts(segment1, segment2, HIGH) || abuts(segment1, segment2, LOW); } struct y_s_e_intersects : gtl_yes {}; template <typename Segment1, typename Segment2> typename enable_if< typename gtl_and_3< y_s_e_intersects, typename is_segment_concept< typename geometry_concept<Segment1>::type >::type, typename is_segment_concept< typename geometry_concept<Segment2>::type >::type >::type, bool >::type intersects(const Segment1& segment1, const Segment2& segment2, bool consider_touch = true) { rectangle_data<typename segment_coordinate_type<Segment1>::type> rect1, rect2; set_points(rect1, low(segment1), high(segment1)); set_points(rect2, low(segment2), high(segment2)); // Check if axis-parallel rectangles containing segments intersect. if (!intersects(rect1, rect2, true)) return false; int or1_1 = orientation(segment1, low(segment2)); int or1_2 = orientation(segment1, high(segment2)); if (or1_1 * or1_2 > 0) return false; int or2_1 = orientation(segment2, low(segment1)); int or2_2 = orientation(segment2, high(segment1)); if (or2_1 * or2_2 > 0) return false; if (consider_touch || (or1_1 && or1_2) || (or2_1 && or2_2)) return true; if (or1_1 || or1_2) return false; return intersects(vertical(rect1), vertical(rect2), false) || intersects(horizontal(rect1), horizontal(rect2), false); } struct y_s_e_dist : gtl_yes {}; template <typename Segment, typename Point> typename enable_if< typename gtl_and_3< y_s_e_dist, typename is_segment_concept< typename geometry_concept<Segment>::type >::type, typename is_point_concept< typename geometry_concept<Point>::type >::type >::type, typename segment_distance_type<Segment>::type>::type euclidean_distance(const Segment& segment, const Point& point) { typedef typename segment_distance_type<Segment>::type Unit; Unit x1 = x(low(segment)); Unit y1 = y(low(segment)); Unit x2 = x(high(segment)); Unit y2 = y(high(segment)); Unit X = x(point); Unit Y = y(point); Unit A = X - x1; Unit B = Y - y1; Unit C = x2 - x1; Unit D = y2 - y1; Unit param = (A * C + B * D); Unit length_sq = C * C + D * D; if (param > length_sq) { return euclidean_distance(high(segment), point); } else if (param < 0.0) { return euclidean_distance(low(segment), point); } if (length_sq == 0.0) return 0.0; Unit denom = std::sqrt(length_sq); Unit result = (A * D - C * B) / denom; return (result < 0.0) ? -result : result; } struct y_s_e_dist2 : gtl_yes {}; template <typename Segment1, typename Segment2> typename enable_if< typename gtl_and_3< y_s_e_dist2, typename is_segment_concept< typename geometry_concept<Segment1>::type >::type, typename is_segment_concept< typename geometry_concept<Segment2>::type >::type >::type, typename segment_distance_type<Segment1>::type>::type euclidean_distance(const Segment1& segment1, const Segment2& segment2) { if (intersects(segment1, segment2)) return 0.0; typename segment_distance_type<Segment1>::type result1 = euclidean_distance(segment1, low(segment2)), result2 = euclidean_distance(segment1, high(segment2)), result3 = euclidean_distance(segment2, low(segment1)), result4 = euclidean_distance(segment2, high(segment1)); if (result2 < result1) result1 = result2; if (result4 < result3) result3 = result4; return (result1 < result3) ? result1 : result3; } } // polygon } // boost #endif // BOOST_POLYGON_SEGMENT_CONCEPT_HPP interval_concept.hpp 0000644 00000062611 15125572616 0010634 0 ustar 00 // Boost.Polygon library interval_concept.hpp header file // Copyright (c) Intel Corporation 2008. // Copyright (c) 2008-2012 Simonson Lucanus. // Copyright (c) 2012-2012 Andrii Sydorchuk. // See http://www.boost.org for updates, documentation, and revision history. // Use, modification and distribution is 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_INTERVAL_CONCEPT_HPP #define BOOST_POLYGON_INTERVAL_CONCEPT_HPP #include "isotropy.hpp" #include "interval_traits.hpp" namespace boost { namespace polygon { struct interval_concept {}; template <typename ConceptType> struct is_interval_concept { typedef gtl_no type; }; template <> struct is_interval_concept<interval_concept> { typedef gtl_yes type; }; template <typename ConceptType> struct is_mutable_interval_concept { typedef gtl_no type; }; template <> struct is_mutable_interval_concept<interval_concept> { typedef gtl_yes type; }; template <typename GeometryType, typename BoolType> struct interval_coordinate_type_by_concept { typedef void type; }; template <typename GeometryType> struct interval_coordinate_type_by_concept<GeometryType, gtl_yes> { typedef typename interval_traits<GeometryType>::coordinate_type type; }; template <typename GeometryType> struct interval_coordinate_type { typedef typename interval_coordinate_type_by_concept< GeometryType, typename is_interval_concept< typename geometry_concept<GeometryType>::type >::type >::type type; }; template <typename GeometryType, typename BoolType> struct interval_difference_type_by_concept { typedef void type; }; template <typename GeometryType> struct interval_difference_type_by_concept<GeometryType, gtl_yes> { typedef typename coordinate_traits< typename interval_traits<GeometryType>::coordinate_type >::coordinate_difference type; }; template <typename GeometryType> struct interval_difference_type { typedef typename interval_difference_type_by_concept< GeometryType, typename is_interval_concept< typename geometry_concept<GeometryType>::type >::type >::type type; }; struct y_i_get : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_get, typename is_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, typename interval_coordinate_type<IntervalType>::type >::type get(const IntervalType& interval, direction_1d dir) { return interval_traits<IntervalType>::get(interval, dir); } struct y_i_set : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_set, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, void >::type set(IntervalType& interval, direction_1d dir, typename interval_mutable_traits<IntervalType>::coordinate_type value) { interval_mutable_traits<IntervalType>::set(interval, dir, value); } struct y_i_construct : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_construct, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, IntervalType >::type construct( typename interval_mutable_traits<IntervalType>::coordinate_type low, typename interval_mutable_traits<IntervalType>::coordinate_type high) { if (low > high) { (std::swap)(low, high); } return interval_mutable_traits<IntervalType>::construct(low, high); } struct y_i_copy_construct : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_copy_construct, typename is_mutable_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, IntervalType1 >::type copy_construct(const IntervalType2& interval) { return construct<IntervalType1>(get(interval, LOW), get(interval, HIGH)); } struct y_i_assign : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_assign, typename is_mutable_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, IntervalType1 >::type& assign(IntervalType1& lvalue, const IntervalType2& rvalue) { set(lvalue, LOW, get(rvalue, LOW)); set(lvalue, HIGH, get(rvalue, HIGH)); return lvalue; } struct y_i_low : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_low, typename is_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, typename interval_coordinate_type<IntervalType>::type >::type low(const IntervalType& interval) { return get(interval, LOW); } struct y_i_high : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_high, typename is_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, typename interval_coordinate_type<IntervalType>::type >::type high(const IntervalType& interval) { return get(interval, HIGH); } struct y_i_low2 : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_low2, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, void >::type low(IntervalType& interval, typename interval_mutable_traits<IntervalType>::coordinate_type value) { set(interval, LOW, value); } struct y_i_high2 : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_high2, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, void >::type high(IntervalType& interval, typename interval_mutable_traits<IntervalType>::coordinate_type value) { set(interval, HIGH, value); } struct y_i_equivalence : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_equivalence, typename is_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, bool >::type equivalence( const IntervalType1& interval1, const IntervalType2& interval2) { return (get(interval1, LOW) == get(interval2, LOW)) && (get(interval1, HIGH) == get(interval2, HIGH)); } struct y_i_contains : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_contains, typename is_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, bool >::type contains( const IntervalType& interval, typename interval_coordinate_type<IntervalType>::type value, bool consider_touch = true ) { if (consider_touch) { return value <= high(interval) && value >= low(interval); } else { return value < high(interval) && value > low(interval); } } struct y_i_contains2 : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_contains2, typename is_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, bool >::type contains( const IntervalType1& interval1, const IntervalType2& interval2, bool consider_touch = true) { return contains(interval1, get(interval2, LOW), consider_touch) && contains(interval1, get(interval2, HIGH), consider_touch); } struct y_i_center : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_center, typename is_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, typename interval_coordinate_type<IntervalType>::type >::type center(const IntervalType& interval) { return (high(interval) + low(interval)) / 2; } struct y_i_delta : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_delta, typename is_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, typename interval_difference_type<IntervalType>::type >::type delta(const IntervalType& interval) { typedef typename interval_difference_type<IntervalType>::type diff_type; return static_cast<diff_type>(high(interval)) - static_cast<diff_type>(low(interval)); } struct y_i_flip : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_flip, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, IntervalType>::type& flip( IntervalType& interval, typename interval_coordinate_type<IntervalType>::type axis = 0) { typename interval_coordinate_type<IntervalType>::type newLow, newHigh; newLow = 2 * axis - high(interval); newHigh = 2 * axis - low(interval); low(interval, newLow); high(interval, newHigh); return interval; } struct y_i_scale_up : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_scale_up, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, IntervalType >::type& scale_up( IntervalType& interval, typename interval_coordinate_type<IntervalType>::type factor) { typename interval_coordinate_type<IntervalType>::type newHigh = high(interval) * factor; low(interval, low(interval) * factor); high(interval, (newHigh)); return interval; } struct y_i_scale_down : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_scale_down, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, IntervalType >::type& scale_down( IntervalType& interval, typename interval_coordinate_type<IntervalType>::type factor) { typename interval_coordinate_type<IntervalType>::type newHigh = high(interval) / factor; low(interval, low(interval) / factor); high(interval, (newHigh)); return interval; } // TODO(asydorchuk): Deprecated. struct y_i_scale : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_scale, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, IntervalType >::type& scale(IntervalType& interval, double factor) { typedef typename interval_coordinate_type<IntervalType>::type Unit; Unit newHigh = scaling_policy<Unit>::round( static_cast<double>(high(interval)) * factor); low(interval, scaling_policy<Unit>::round( static_cast<double>(low(interval)) * factor)); high(interval, (newHigh)); return interval; } struct y_i_move : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_move, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, IntervalType >::type& move( IntervalType& interval, typename interval_difference_type<IntervalType>::type displacement) { typedef typename interval_coordinate_type<IntervalType>::type ctype; typedef typename coordinate_traits<ctype>::coordinate_difference Unit; low(interval, static_cast<ctype>( static_cast<Unit>(low(interval)) + displacement)); high(interval, static_cast<ctype>( static_cast<Unit>(high(interval)) + displacement)); return interval; } struct y_i_convolve : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_convolve, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, IntervalType >::type& convolve( IntervalType& interval, typename interval_coordinate_type<IntervalType>::type value) { typedef typename interval_coordinate_type<IntervalType>::type Unit; Unit newLow = low(interval) + value; Unit newHigh = high(interval) + value; low(interval, newLow); high(interval, newHigh); return interval; } struct y_i_deconvolve : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_deconvolve, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, IntervalType >::type& deconvolve( IntervalType& interval, typename interval_coordinate_type<IntervalType>::type value) { typedef typename interval_coordinate_type<IntervalType>::type Unit; Unit newLow = low(interval) - value; Unit newHigh = high(interval) - value; low(interval, newLow); high(interval, newHigh); return interval; } struct y_i_convolve2 : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_convolve2, typename is_mutable_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, IntervalType1 >::type& convolve(IntervalType1& lvalue, const IntervalType2& rvalue) { typedef typename interval_coordinate_type<IntervalType1>::type Unit; Unit newLow = low(lvalue) + low(rvalue); Unit newHigh = high(lvalue) + high(rvalue); low(lvalue, newLow); high(lvalue, newHigh); return lvalue; } struct y_i_deconvolve2 : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_deconvolve2, typename is_mutable_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, IntervalType1 >::type& deconvolve(IntervalType1& lvalue, const IntervalType2& rvalue) { typedef typename interval_coordinate_type<IntervalType1>::type Unit; Unit newLow = low(lvalue) - low(rvalue); Unit newHigh = high(lvalue) - high(rvalue); low(lvalue, newLow); high(lvalue, newHigh); return lvalue; } struct y_i_reconvolve : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_reconvolve, typename is_mutable_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, IntervalType1 >::type& reflected_convolve( IntervalType1& lvalue, const IntervalType2& rvalue) { typedef typename interval_coordinate_type<IntervalType1>::type Unit; Unit newLow = low(lvalue) - high(rvalue); Unit newHigh = high(lvalue) - low(rvalue); low(lvalue, newLow); high(lvalue, newHigh); return lvalue; } struct y_i_redeconvolve : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_redeconvolve, typename is_mutable_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, IntervalType1 >::type& reflected_deconvolve( IntervalType1& lvalue, const IntervalType2& rvalue) { typedef typename interval_coordinate_type<IntervalType1>::type Unit; Unit newLow = low(lvalue) + high(rvalue); Unit newHigh = high(lvalue) + low(rvalue); low(lvalue, newLow); high(lvalue, newHigh); return lvalue; } struct y_i_e_dist1 : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and<y_i_e_dist1, typename is_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, typename interval_difference_type<IntervalType>::type >::type euclidean_distance( const IntervalType& interval, typename interval_coordinate_type<IntervalType>::type position) { typedef typename interval_difference_type<IntervalType>::type Unit; Unit dist[3] = { 0, (Unit)low(interval) - (Unit)position, (Unit)position - (Unit)high(interval) }; return dist[(dist[1] > 0) + ((dist[2] > 0) << 1)]; } struct y_i_e_dist2 : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_e_dist2, typename is_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, typename interval_difference_type<IntervalType1>::type >::type euclidean_distance( const IntervalType1& interval1, const IntervalType2& interval2) { typedef typename interval_difference_type<IntervalType1>::type Unit; Unit dist[3] = { 0, (Unit)low(interval1) - (Unit)high(interval2), (Unit)low(interval2) - (Unit)high(interval1) }; return dist[(dist[1] > 0) + ((dist[2] > 0) << 1)]; } struct y_i_e_intersects : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_e_intersects, typename is_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, bool >::type intersects( const IntervalType1& interval1, const IntervalType2& interval2, bool consider_touch = true) { return consider_touch ? (low(interval1) <= high(interval2)) && (high(interval1) >= low(interval2)) : (low(interval1) < high(interval2)) && (high(interval1) > low(interval2)); } struct y_i_e_bintersect : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_e_bintersect, typename is_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, bool >::type boundaries_intersect( const IntervalType1& interval1, const IntervalType2& interval2, bool consider_touch = true) { return (contains(interval1, low(interval2), consider_touch) || contains(interval1, high(interval2), consider_touch)) && (contains(interval2, low(interval1), consider_touch) || contains(interval2, high(interval1), consider_touch)); } struct y_i_intersect : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_intersect, typename is_mutable_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, bool >::type intersect( IntervalType1& lvalue, const IntervalType2& rvalue, bool consider_touch = true) { typedef typename interval_coordinate_type<IntervalType1>::type Unit; Unit lowVal = (std::max)(low(lvalue), low(rvalue)); Unit highVal = (std::min)(high(lvalue), high(rvalue)); bool valid = consider_touch ? lowVal <= highVal : lowVal < highVal; if (valid) { low(lvalue, lowVal); high(lvalue, highVal); } return valid; } struct y_i_g_intersect : gtl_yes {}; // TODO(asydorchuk): Deprecated. template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_g_intersect, typename is_mutable_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, IntervalType1 >::type& generalized_intersect( IntervalType1& lvalue, const IntervalType2& rvalue) { typedef typename interval_coordinate_type<IntervalType1>::type Unit; Unit coords[4] = {low(lvalue), high(lvalue), low(rvalue), high(rvalue)}; // TODO(asydorchuk): consider implementing faster sorting of small // fixed length range. polygon_sort(coords, coords+4); low(lvalue, coords[1]); high(lvalue, coords[2]); return lvalue; } struct y_i_abuts1 : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_abuts1, typename is_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, bool >::type abuts( const IntervalType1& interval1, const IntervalType2& interval2, direction_1d dir) { return dir.to_int() ? low(interval2) == high(interval1) : low(interval1) == high(interval2); } struct y_i_abuts2 : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_abuts2, typename is_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, bool >::type abuts( const IntervalType1& interval1, const IntervalType2& interval2) { return abuts(interval1, interval2, HIGH) || abuts(interval1, interval2, LOW); } struct y_i_bloat : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_bloat, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, IntervalType >::type& bloat( IntervalType& interval, typename interval_coordinate_type<IntervalType>::type bloating) { low(interval, low(interval) - bloating); high(interval, high(interval) + bloating); return interval; } struct y_i_bloat2 : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_bloat2, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, IntervalType >::type& bloat( IntervalType& interval, direction_1d dir, typename interval_coordinate_type<IntervalType>::type bloating) { set(interval, dir, get(interval, dir) + dir.get_sign() * bloating); return interval; } struct y_i_shrink : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_shrink, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, IntervalType >::type& shrink( IntervalType& interval, typename interval_coordinate_type<IntervalType>::type shrinking) { return bloat(interval, -shrinking); } struct y_i_shrink2 : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_shrink2, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, IntervalType >::type& shrink( IntervalType& interval, direction_1d dir, typename interval_coordinate_type<IntervalType>::type shrinking) { return bloat(interval, dir, -shrinking); } struct y_i_encompass : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_encompass, typename is_mutable_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type >::type, bool >::type encompass(IntervalType1& interval1, const IntervalType2& interval2) { bool retval = !contains(interval1, interval2, true); low(interval1, (std::min)(low(interval1), low(interval2))); high(interval1, (std::max)(high(interval1), high(interval2))); return retval; } struct y_i_encompass2 : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_encompass2, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, bool >::type encompass( IntervalType& interval, typename interval_coordinate_type<IntervalType>::type value) { bool retval = !contains(interval, value, true); low(interval, (std::min)(low(interval), value)); high(interval, (std::max)(high(interval), value)); return retval; } struct y_i_get_half : gtl_yes {}; template <typename IntervalType> typename enable_if< typename gtl_and< y_i_get_half, typename is_mutable_interval_concept< typename geometry_concept<IntervalType>::type >::type >::type, IntervalType >::type get_half(const IntervalType& interval, direction_1d dir) { typedef typename interval_coordinate_type<IntervalType>::type Unit; Unit c = (get(interval, LOW) + get(interval, HIGH)) / 2; return construct<IntervalType>( (dir == LOW) ? get(interval, LOW) : c, (dir == LOW) ? c : get(interval, HIGH)); } struct y_i_join_with : gtl_yes {}; template <typename IntervalType1, typename IntervalType2> typename enable_if< typename gtl_and_3< y_i_join_with, typename is_mutable_interval_concept< typename geometry_concept<IntervalType1>::type >::type, typename is_interval_concept< typename geometry_concept<IntervalType2>::type >::type>::type, bool >::type join_with(IntervalType1& interval1, const IntervalType2& interval2) { if (abuts(interval1, interval2)) { encompass(interval1, interval2); return true; } return false; } } // polygon } // boost #endif // BOOST_POLYGON_INTERVAL_CONCEPT_HPP point_data.hpp 0000644 00000006264 15125572616 0007421 0 ustar 00 // Boost.Polygon library point_data.hpp header file // Copyright (c) Intel Corporation 2008. // Copyright (c) 2008-2012 Simonson Lucanus. // Copyright (c) 2012-2012 Andrii Sydorchuk. // See http://www.boost.org for updates, documentation, and revision history. // Use, modification and distribution is 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_POINT_DATA_HPP #define BOOST_POLYGON_POINT_DATA_HPP #include "isotropy.hpp" #include "point_concept.hpp" namespace boost { namespace polygon { template <typename T> class point_data { public: typedef T coordinate_type; point_data() #ifndef BOOST_POLYGON_MSVC : coords_() #endif {} point_data(coordinate_type x, coordinate_type y) { coords_[HORIZONTAL] = x; coords_[VERTICAL] = y; } explicit point_data(const point_data& that) { coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; } point_data& operator=(const point_data& that) { coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; return *this; } #if defined(__GNUC__) && __GNUC__ < 6 // "explicit" to work around a bug in GCC < 6: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63356 template <typename PointType> explicit point_data(const PointType& that) { *this = that; } #else // __GNUC__ < 6 template <typename PointType> point_data(const PointType& that) { *this = that; } #endif // __GNUC__ < 6 template <typename PointType> point_data& operator=(const PointType& that) { assign(*this, that); return *this; } // TODO(asydorchuk): Deprecated. template <typename CT> point_data(const point_data<CT>& that) { coords_[HORIZONTAL] = (coordinate_type)that.x(); coords_[VERTICAL] = (coordinate_type)that.y(); } coordinate_type get(orientation_2d orient) const { return coords_[orient.to_int()]; } void set(orientation_2d orient, coordinate_type value) { coords_[orient.to_int()] = value; } coordinate_type x() const { return coords_[HORIZONTAL]; } point_data& x(coordinate_type value) { coords_[HORIZONTAL] = value; return *this; } coordinate_type y() const { return coords_[VERTICAL]; } point_data& y(coordinate_type value) { coords_[VERTICAL] = value; return *this; } bool operator==(const point_data& that) const { return (coords_[0] == that.coords_[0]) && (coords_[1] == that.coords_[1]); } bool operator!=(const point_data& that) const { return !(*this == that); } bool operator<(const point_data& that) const { return (coords_[0] < that.coords_[0]) || ((coords_[0] == that.coords_[0]) && (coords_[1] < that.coords_[1])); } bool operator<=(const point_data& that) const { return !(that < *this); } bool operator>(const point_data& that) const { return that < *this; } bool operator>=(const point_data& that) const { return !(*this < that); } private: coordinate_type coords_[2]; }; template <typename CType> struct geometry_concept< point_data<CType> > { typedef point_concept type; }; } // polygon } // boost #endif // BOOST_POLYGON_POINT_DATA_HPP gmp_override.hpp 0000644 00000006255 15125572616 0007761 0 ustar 00 /* 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_GMP_OVERRIDE_HPP #define BOOST_POLYGON_GMP_OVERRIDE_HPP #include <gmpxx.h> namespace boost { namespace polygon { class gmp_int { private: inline gmp_int(const mpq_class& input) : v_(input) {} public: inline gmp_int() {} explicit inline gmp_int(long input) : v_(input) {} inline gmp_int(const gmp_int& input) : v_(input.v_) {} inline gmp_int& operator=(const gmp_int& that) { v_ = that.v_; return (*this); } inline gmp_int& operator=(long that) { v_ = that; return (*this); } inline operator int() const { std::cout << "cast\n"; mpz_class num = v_.get_num(); mpz_class den = v_.get_den(); num /= den; return num.get_si(); } inline double get_d() const { return v_.get_d(); } inline int get_num() const { return v_.get_num().get_si(); } inline int get_den() const { return v_.get_den().get_si(); } inline bool operator==(const gmp_int& that) const { return v_ == that.v_; } inline bool operator!=(const gmp_int& that) const { return v_ != that.v_; } inline bool operator<(const gmp_int& that) const { bool retval = v_ < that.v_; return retval; } inline bool operator<=(const gmp_int& that) const { return v_ <= that.v_; } inline bool operator>(const gmp_int& that) const { return v_ > that.v_; } inline bool operator>=(const gmp_int& that) const { return v_ >= that.v_; } inline gmp_int operator+(const gmp_int& b) { return gmp_int((*this).v_ + b.v_); } inline gmp_int operator-(const gmp_int& b) { return gmp_int((*this).v_ - b.v_); } inline gmp_int operator*(const gmp_int& b) { return gmp_int((*this).v_ * b.v_); } inline gmp_int operator/(const gmp_int& b) { return gmp_int((*this).v_ / b.v_); } inline gmp_int& operator+=(const gmp_int& b) { (*this).v_ += b.v_; return (*this); } inline gmp_int& operator-=(const gmp_int& b) { (*this).v_ -= b.v_; return (*this); } inline gmp_int& operator*=(const gmp_int& b) { (*this).v_ *= b.v_; return (*this); } inline gmp_int& operator/=(const gmp_int& b) { (*this).v_ /= b.v_; return (*this); } inline gmp_int& operator++() { ++v_; return (*this); } inline gmp_int& operator--() { --v_; return (*this); } inline gmp_int operator++(int) { gmp_int retval(*this); ++(*this); return retval; } inline gmp_int operator--(int) { gmp_int retval(*this); --(*this); return retval; } private: mpq_class v_; }; template <> struct high_precision_type<int> { typedef mpq_class type; }; template <> int convert_high_precision_type<int>(const mpq_class& v) { mpz_class num = v.get_num(); mpz_class den = v.get_den(); num /= den; return num.get_si(); }; } } #endif transform.hpp 0000644 00000035234 15125572616 0007311 0 ustar 00 // Boost.Polygon library transform.hpp header file // Copyright (c) Intel Corporation 2008. // Copyright (c) 2008-2012 Simonson Lucanus. // Copyright (c) 2012-2012 Andrii Sydorchuk. // See http://www.boost.org for updates, documentation, and revision history. // Use, modification and distribution is 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_TRANSFORM_HPP #define BOOST_POLYGON_TRANSFORM_HPP #include "isotropy.hpp" namespace boost { namespace polygon { // Transformation of Coordinate System. // Enum meaning: // Select which direction_2d to change the positive direction of each // axis in the old coordinate system to map it to the new coordiante system. // The first direction_2d listed for each enum is the direction to map the // positive horizontal direction to. // The second direction_2d listed for each enum is the direction to map the // positive vertical direction to. // The zero position bit (LSB) indicates whether the horizontal axis flips // when transformed. // The 1st postion bit indicates whether the vertical axis flips when // transformed. // The 2nd position bit indicates whether the horizontal and vertical axis // swap positions when transformed. // Enum Values: // 000 EAST NORTH // 001 WEST NORTH // 010 EAST SOUTH // 011 WEST SOUTH // 100 NORTH EAST // 101 SOUTH EAST // 110 NORTH WEST // 111 SOUTH WEST class axis_transformation { public: enum ATR { #ifdef BOOST_POLYGON_ENABLE_DEPRECATED EN = 0, WN = 1, ES = 2, WS = 3, NE = 4, SE = 5, NW = 6, SW = 7, #endif NULL_TRANSFORM = 0, BEGIN_TRANSFORM = 0, EAST_NORTH = 0, WEST_NORTH = 1, FLIP_X = 1, EAST_SOUTH = 2, FLIP_Y = 2, WEST_SOUTH = 3, FLIP_XY = 3, NORTH_EAST = 4, SWAP_XY = 4, SOUTH_EAST = 5, ROTATE_LEFT = 5, NORTH_WEST = 6, ROTATE_RIGHT = 6, SOUTH_WEST = 7, FLIP_SWAP_XY = 7, END_TRANSFORM = 7 }; // Individual axis enum values indicate which axis an implicit individual // axis will be mapped to. // The value of the enum paired with an axis provides the information // about what the axis will transform to. // Three individual axis values, one for each axis, are equivalent to one // ATR enum value, but easier to work with because they are independent. // Converting to and from the individual axis values from the ATR value // is a convenient way to implement tranformation related functionality. // Enum meanings: // PX: map to positive x axis // NX: map to negative x axis // PY: map to positive y axis // NY: map to negative y axis enum INDIVIDUAL_AXIS { PX = 0, NX = 1, PY = 2, NY = 3 }; axis_transformation() : atr_(NULL_TRANSFORM) {} explicit axis_transformation(ATR atr) : atr_(atr) {} axis_transformation(const axis_transformation& atr) : atr_(atr.atr_) {} explicit axis_transformation(const orientation_2d& orient) { const ATR tmp[2] = { NORTH_EAST, // sort x, then y EAST_NORTH // sort y, then x }; atr_ = tmp[orient.to_int()]; } explicit axis_transformation(const direction_2d& dir) { const ATR tmp[4] = { SOUTH_EAST, // sort x, then y NORTH_EAST, // sort x, then y EAST_SOUTH, // sort y, then x EAST_NORTH // sort y, then x }; atr_ = tmp[dir.to_int()]; } // assignment operator axis_transformation& operator=(const axis_transformation& a) { atr_ = a.atr_; return *this; } // assignment operator axis_transformation& operator=(const ATR& atr) { atr_ = atr; return *this; } // equivalence operator bool operator==(const axis_transformation& a) const { return atr_ == a.atr_; } // inequivalence operator bool operator!=(const axis_transformation& a) const { return !(*this == a); } // ordering bool operator<(const axis_transformation& a) const { return atr_ < a.atr_; } // concatenate this with that axis_transformation& operator+=(const axis_transformation& a) { bool abit2 = (a.atr_ & 4) != 0; bool abit1 = (a.atr_ & 2) != 0; bool abit0 = (a.atr_ & 1) != 0; bool bit2 = (atr_ & 4) != 0; bool bit1 = (atr_ & 2) != 0; bool bit0 = (atr_ & 1) != 0; int indexes[2][2] = { { (int)bit2, (int)(!bit2) }, { (int)abit2, (int)(!abit2) } }; int zero_bits[2][2] = { {bit0, bit1}, {abit0, abit1} }; int nbit1 = zero_bits[0][1] ^ zero_bits[1][indexes[0][1]]; int nbit0 = zero_bits[0][0] ^ zero_bits[1][indexes[0][0]]; indexes[0][0] = indexes[1][indexes[0][0]]; indexes[0][1] = indexes[1][indexes[0][1]]; int nbit2 = indexes[0][0] & 1; // swap xy atr_ = (ATR)((nbit2 << 2) + (nbit1 << 1) + nbit0); return *this; } // concatenation operator axis_transformation operator+(const axis_transformation& a) const { axis_transformation retval(*this); return retval+=a; } // populate_axis_array writes the three INDIVIDUAL_AXIS values that the // ATR enum value of 'this' represent into axis_array void populate_axis_array(INDIVIDUAL_AXIS axis_array[]) const { bool bit2 = (atr_ & 4) != 0; bool bit1 = (atr_ & 2) != 0; bool bit0 = (atr_ & 1) != 0; axis_array[1] = (INDIVIDUAL_AXIS)(((int)(!bit2) << 1) + bit1); axis_array[0] = (INDIVIDUAL_AXIS)(((int)(bit2) << 1) + bit0); } // it is recommended that the directions stored in an array // in the caller code for easier isotropic access by orientation value void get_directions(direction_2d& horizontal_dir, direction_2d& vertical_dir) const { bool bit2 = (atr_ & 4) != 0; bool bit1 = (atr_ & 2) != 0; bool bit0 = (atr_ & 1) != 0; vertical_dir = direction_2d((direction_2d_enum)(((int)(!bit2) << 1) + !bit1)); horizontal_dir = direction_2d((direction_2d_enum)(((int)(bit2) << 1) + !bit0)); } // combine_axis_arrays concatenates this_array and that_array overwriting // the result into this_array static void combine_axis_arrays(INDIVIDUAL_AXIS this_array[], const INDIVIDUAL_AXIS that_array[]) { int indexes[2] = { this_array[0] >> 1, this_array[1] >> 1 }; int zero_bits[2][2] = { { this_array[0] & 1, this_array[1] & 1 }, { that_array[0] & 1, that_array[1] & 1 } }; this_array[0] = (INDIVIDUAL_AXIS)((int)this_array[0] | ((int)zero_bits[0][0] ^ (int)zero_bits[1][indexes[0]])); this_array[1] = (INDIVIDUAL_AXIS)((int)this_array[1] | ((int)zero_bits[0][1] ^ (int)zero_bits[1][indexes[1]])); } // write_back_axis_array converts an array of three INDIVIDUAL_AXIS values // to the ATR enum value and sets 'this' to that value void write_back_axis_array(const INDIVIDUAL_AXIS this_array[]) { int bit2 = ((int)this_array[0] & 2) != 0; // swap xy int bit1 = ((int)this_array[1] & 1); int bit0 = ((int)this_array[0] & 1); atr_ = ATR((bit2 << 2) + (bit1 << 1) + bit0); } // behavior is deterministic but undefined in the case where illegal // combinations of directions are passed in. axis_transformation& set_directions(const direction_2d& horizontal_dir, const direction_2d& vertical_dir) { int bit2 = (static_cast<orientation_2d>(horizontal_dir).to_int()) != 0; int bit1 = !(vertical_dir.to_int() & 1); int bit0 = !(horizontal_dir.to_int() & 1); atr_ = ATR((bit2 << 2) + (bit1 << 1) + bit0); return *this; } // transform the three coordinates by reference template <typename coordinate_type> void transform(coordinate_type& x, coordinate_type& y) const { int bit2 = (atr_ & 4) != 0; int bit1 = (atr_ & 2) != 0; int bit0 = (atr_ & 1) != 0; x *= -((bit0 << 1) - 1); y *= -((bit1 << 1) - 1); predicated_swap(bit2 != 0, x, y); } // invert this axis_transformation axis_transformation& invert() { int bit2 = ((atr_ & 4) != 0); int bit1 = ((atr_ & 2) != 0); int bit0 = ((atr_ & 1) != 0); // swap bit 0 and bit 1 if bit2 is 1 predicated_swap(bit2 != 0, bit0, bit1); bit1 = bit1 << 1; atr_ = (ATR)(atr_ & (32+16+8+4)); // mask away bit0 and bit1 atr_ = (ATR)(atr_ | bit0 | bit1); return *this; } // get the inverse axis_transformation of this axis_transformation inverse() const { axis_transformation retval(*this); return retval.invert(); } private: ATR atr_; }; // Scaling object to be used to store the scale factor for each axis. // For use by the transformation object, in that context the scale factor // is the amount that each axis scales by when transformed. template <typename scale_factor_type> class anisotropic_scale_factor { public: anisotropic_scale_factor() { scale_[0] = 1; scale_[1] = 1; } anisotropic_scale_factor(scale_factor_type xscale, scale_factor_type yscale) { scale_[0] = xscale; scale_[1] = yscale; } // get a component of the anisotropic_scale_factor by orientation scale_factor_type get(orientation_2d orient) const { return scale_[orient.to_int()]; } // set a component of the anisotropic_scale_factor by orientation void set(orientation_2d orient, scale_factor_type value) { scale_[orient.to_int()] = value; } scale_factor_type x() const { return scale_[HORIZONTAL]; } scale_factor_type y() const { return scale_[VERTICAL]; } void x(scale_factor_type value) { scale_[HORIZONTAL] = value; } void y(scale_factor_type value) { scale_[VERTICAL] = value; } // concatination operator (convolve scale factors) anisotropic_scale_factor operator+(const anisotropic_scale_factor& s) const { anisotropic_scale_factor<scale_factor_type> retval(*this); return retval += s; } // concatinate this with that const anisotropic_scale_factor& operator+=( const anisotropic_scale_factor& s) { scale_[0] *= s.scale_[0]; scale_[1] *= s.scale_[1]; return *this; } // transform this scale with an axis_transform anisotropic_scale_factor& transform(axis_transformation atr) { direction_2d dirs[2]; atr.get_directions(dirs[0], dirs[1]); scale_factor_type tmp[2] = {scale_[0], scale_[1]}; for (int i = 0; i < 2; ++i) { scale_[orientation_2d(dirs[i]).to_int()] = tmp[i]; } return *this; } // scale the two coordinates template <typename coordinate_type> void scale(coordinate_type& x, coordinate_type& y) const { x = scaling_policy<coordinate_type>::round( (scale_factor_type)x * get(HORIZONTAL)); y = scaling_policy<coordinate_type>::round( (scale_factor_type)y * get(HORIZONTAL)); } // invert this scale factor to give the reverse scale factor anisotropic_scale_factor& invert() { x(1/x()); y(1/y()); return *this; } private: scale_factor_type scale_[2]; }; // Transformation object, stores and provides services for transformations. // Consits of axis transformation, scale factor and translation. // The tranlation is the position of the origin of the new coordinate system of // in the old system. Coordinates are scaled before they are transformed. template <typename coordinate_type> class transformation { public: transformation() : atr_(), p_(0, 0) {} explicit transformation(axis_transformation atr) : atr_(atr), p_(0, 0) {} explicit transformation(axis_transformation::ATR atr) : atr_(atr), p_(0, 0) {} transformation(const transformation& tr) : atr_(tr.atr_), p_(tr.p_) {} template <typename point_type> explicit transformation(const point_type& p) : atr_(), p_(0, 0) { set_translation(p); } template <typename point_type> transformation(axis_transformation atr, const point_type& p) : atr_(atr), p_(0, 0) { set_translation(p); } template <typename point_type> transformation(axis_transformation atr, const point_type& referencePt, const point_type& destinationPt) : atr_(), p_(0, 0) { transformation<coordinate_type> tmp(referencePt); transformation<coordinate_type> rotRef(atr); transformation<coordinate_type> tmpInverse = tmp.inverse(); point_type decon(referencePt); deconvolve(decon, destinationPt); transformation<coordinate_type> displacement(decon); tmp += rotRef; tmp += tmpInverse; tmp += displacement; (*this) = tmp; } // equivalence operator bool operator==(const transformation& tr) const { return (atr_ == tr.atr_) && (p_ == tr.p_); } // inequivalence operator bool operator!=(const transformation& tr) const { return !(*this == tr); } // ordering bool operator<(const transformation& tr) const { return (atr_ < tr.atr_) || ((atr_ == tr.atr_) && (p_ < tr.p_)); } // concatenation operator transformation operator+(const transformation& tr) const { transformation<coordinate_type> retval(*this); return retval+=tr; } // concatenate this with that const transformation& operator+=(const transformation& tr) { coordinate_type x, y; transformation<coordinate_type> inv = inverse(); inv.transform(x, y); p_.set(HORIZONTAL, p_.get(HORIZONTAL) + x); p_.set(VERTICAL, p_.get(VERTICAL) + y); // concatenate axis transforms atr_ += tr.atr_; return *this; } // get the axis_transformation portion of this axis_transformation get_axis_transformation() const { return atr_; } // set the axis_transformation portion of this void set_axis_transformation(const axis_transformation& atr) { atr_ = atr; } // get the translation template <typename point_type> void get_translation(point_type& p) const { assign(p, p_); } // set the translation template <typename point_type> void set_translation(const point_type& p) { assign(p_, p); } // apply the 2D portion of this transformation to the two coordinates given void transform(coordinate_type& x, coordinate_type& y) const { y -= p_.get(VERTICAL); x -= p_.get(HORIZONTAL); atr_.transform(x, y); } // invert this transformation transformation& invert() { coordinate_type x = p_.get(HORIZONTAL), y = p_.get(VERTICAL); atr_.transform(x, y); x *= -1; y *= -1; p_ = point_data<coordinate_type>(x, y); atr_.invert(); return *this; } // get the inverse of this transformation transformation inverse() const { transformation<coordinate_type> ret_val(*this); return ret_val.invert(); } void get_directions(direction_2d& horizontal_dir, direction_2d& vertical_dir) const { return atr_.get_directions(horizontal_dir, vertical_dir); } private: axis_transformation atr_; point_data<coordinate_type> p_; }; } // polygon } // boost #endif // BOOST_POLYGON_TRANSFORM_HPP polygon_data.hpp 0000644 00000004252 15125572616 0007752 0 ustar 00 /* 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_DATA_HPP #define BOOST_POLYGON_POLYGON_DATA_HPP namespace boost { namespace polygon{ struct polygon_concept; template <typename T> class polygon_data { public: typedef polygon_concept geometry_type; typedef T coordinate_type; typedef typename std::vector<point_data<coordinate_type> >::const_iterator iterator_type; typedef typename coordinate_traits<T>::coordinate_distance area_type; typedef point_data<T> point_type; inline polygon_data() : coords_() {} //do nothing default constructor template<class iT> inline polygon_data(iT input_begin, iT input_end) : coords_(input_begin, input_end) {} template<class iT> inline polygon_data& set(iT input_begin, iT input_end) { coords_.clear(); //just in case there was some old data there coords_.insert(coords_.end(), input_begin, input_end); return *this; } // copy constructor (since we have dynamic memory) inline polygon_data(const polygon_data& that) : coords_(that.coords_) {} // assignment operator (since we have dynamic memory do a deep copy) inline polygon_data& operator=(const polygon_data& that) { coords_ = that.coords_; return *this; } template <typename T2> inline polygon_data& operator=(const T2& rvalue); inline bool operator==(const polygon_data& that) const { if(coords_.size() != that.coords_.size()) return false; for(std::size_t i = 0; i < coords_.size(); ++i) { if(coords_[i] != that.coords_[i]) return false; } return true; } inline bool operator!=(const polygon_data& that) const { return !((*this) == that); } // get begin iterator, returns a pointer to a const Unit inline iterator_type begin() const { return coords_.begin(); } // get end iterator, returns a pointer to a const Unit inline iterator_type end() const { return coords_.end(); } inline std::size_t size() const { return coords_.size(); } public: std::vector<point_data<coordinate_type> > coords_; }; } } #endif voronoi_builder.hpp 0000644 00000046320 15125572616 0010475 0 ustar 00 // Boost.Polygon library voronoi_builder.hpp header file // Copyright Andrii Sydorchuk 2010-2012. // Distributed under 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) // See http://www.boost.org for updates, documentation, and revision history. #ifndef BOOST_POLYGON_VORONOI_BUILDER #define BOOST_POLYGON_VORONOI_BUILDER #include <algorithm> #include <map> #include <queue> #include <utility> #include <vector> #include "detail/voronoi_ctypes.hpp" #include "detail/voronoi_predicates.hpp" #include "detail/voronoi_structures.hpp" #include "voronoi_geometry_type.hpp" namespace boost { namespace polygon { // GENERAL INFO: // The sweepline algorithm implementation to compute Voronoi diagram of // points and non-intersecting segments (excluding endpoints). // Complexity - O(N*logN), memory usage - O(N), where N is the total number // of input geometries. // // CONTRACT: // 1) Input geometries should have integral (e.g. int32, int64) coordinate type. // 2) Input geometries should not intersect except their endpoints. // // IMPLEMENTATION DETAILS: // Each input point creates one input site. Each input segment creates three // input sites: two for its endpoints and one for the segment itself (this is // made to simplify output construction). All the site objects are constructed // and sorted at the algorithm initialization step. Priority queue is used to // dynamically hold circle events. At each step of the algorithm execution the // leftmost event is retrieved by comparing the current site event and the // topmost element from the circle event queue. STL map (red-black tree) // container was chosen to hold state of the beach line. The keys of the map // correspond to the neighboring sites that form a bisector and values map to // the corresponding Voronoi edges in the output data structure. template <typename T, typename CTT = detail::voronoi_ctype_traits<T>, typename VP = detail::voronoi_predicates<CTT> > class voronoi_builder { public: typedef typename CTT::int_type int_type; typedef typename CTT::fpt_type fpt_type; voronoi_builder() : index_(0) {} // Each point creates a single site event. std::size_t insert_point(const int_type& x, const int_type& y) { site_events_.push_back(site_event_type(x, y)); site_events_.back().initial_index(index_); site_events_.back().source_category(SOURCE_CATEGORY_SINGLE_POINT); return index_++; } // Each segment creates three site events that correspond to: // 1) the start point of the segment; // 2) the end point of the segment; // 3) the segment itself defined by its start point. std::size_t insert_segment( const int_type& x1, const int_type& y1, const int_type& x2, const int_type& y2) { // Set up start point site. point_type p1(x1, y1); site_events_.push_back(site_event_type(p1)); site_events_.back().initial_index(index_); site_events_.back().source_category(SOURCE_CATEGORY_SEGMENT_START_POINT); // Set up end point site. point_type p2(x2, y2); site_events_.push_back(site_event_type(p2)); site_events_.back().initial_index(index_); site_events_.back().source_category(SOURCE_CATEGORY_SEGMENT_END_POINT); // Set up segment site. if (point_comparison_(p1, p2)) { site_events_.push_back(site_event_type(p1, p2)); site_events_.back().source_category(SOURCE_CATEGORY_INITIAL_SEGMENT); } else { site_events_.push_back(site_event_type(p2, p1)); site_events_.back().source_category(SOURCE_CATEGORY_REVERSE_SEGMENT); } site_events_.back().initial_index(index_); return index_++; } // Run sweepline algorithm and fill output data structure. template <typename OUTPUT> void construct(OUTPUT* output) { // Init structures. output->_reserve(site_events_.size()); init_sites_queue(); init_beach_line(output); // The algorithm stops when there are no events to process. event_comparison_predicate event_comparison; while (!circle_events_.empty() || !(site_event_iterator_ == site_events_.end())) { if (circle_events_.empty()) { process_site_event(output); } else if (site_event_iterator_ == site_events_.end()) { process_circle_event(output); } else { if (event_comparison(*site_event_iterator_, circle_events_.top().first)) { process_site_event(output); } else { process_circle_event(output); } } while (!circle_events_.empty() && !circle_events_.top().first.is_active()) { circle_events_.pop(); } } beach_line_.clear(); // Finish construction. output->_build(); } void clear() { index_ = 0; site_events_.clear(); } private: typedef detail::point_2d<int_type> point_type; typedef detail::site_event<int_type> site_event_type; typedef typename std::vector<site_event_type>::const_iterator site_event_iterator_type; typedef detail::circle_event<fpt_type> circle_event_type; typedef typename VP::template point_comparison_predicate<point_type> point_comparison_predicate; typedef typename VP:: template event_comparison_predicate<site_event_type, circle_event_type> event_comparison_predicate; typedef typename VP:: template circle_formation_predicate<site_event_type, circle_event_type> circle_formation_predicate_type; typedef void edge_type; typedef detail::beach_line_node_key<site_event_type> key_type; typedef detail::beach_line_node_data<edge_type, circle_event_type> value_type; typedef typename VP::template node_comparison_predicate<key_type> node_comparer_type; typedef std::map< key_type, value_type, node_comparer_type > beach_line_type; typedef typename beach_line_type::iterator beach_line_iterator; typedef std::pair<circle_event_type, beach_line_iterator> event_type; struct event_comparison_type { bool operator()(const event_type& lhs, const event_type& rhs) const { return predicate(rhs.first, lhs.first); } event_comparison_predicate predicate; }; typedef detail::ordered_queue<event_type, event_comparison_type> circle_event_queue_type; typedef std::pair<point_type, beach_line_iterator> end_point_type; void init_sites_queue() { // Sort site events. std::sort(site_events_.begin(), site_events_.end(), event_comparison_predicate()); // Remove duplicates. site_events_.erase(std::unique( site_events_.begin(), site_events_.end()), site_events_.end()); // Index sites. for (std::size_t cur = 0; cur < site_events_.size(); ++cur) { site_events_[cur].sorted_index(cur); } // Init site iterator. site_event_iterator_ = site_events_.begin(); } template <typename OUTPUT> void init_beach_line(OUTPUT* output) { if (site_events_.empty()) return; if (site_events_.size() == 1) { // Handle single site event case. output->_process_single_site(site_events_[0]); ++site_event_iterator_; } else { int skip = 0; while (site_event_iterator_ != site_events_.end() && VP::is_vertical(site_event_iterator_->point0(), site_events_.begin()->point0()) && VP::is_vertical(*site_event_iterator_)) { ++site_event_iterator_; ++skip; } if (skip == 1) { // Init beach line with the first two sites. init_beach_line_default(output); } else { // Init beach line with collinear vertical sites. init_beach_line_collinear_sites(output); } } } // Init beach line with the two first sites. // The first site is always a point. template <typename OUTPUT> void init_beach_line_default(OUTPUT* output) { // Get the first and the second site event. site_event_iterator_type it_first = site_events_.begin(); site_event_iterator_type it_second = site_events_.begin(); ++it_second; insert_new_arc( *it_first, *it_first, *it_second, beach_line_.end(), output); // The second site was already processed. Move the iterator. ++site_event_iterator_; } // Init beach line with collinear sites. template <typename OUTPUT> void init_beach_line_collinear_sites(OUTPUT* output) { site_event_iterator_type it_first = site_events_.begin(); site_event_iterator_type it_second = site_events_.begin(); ++it_second; while (it_second != site_event_iterator_) { // Create a new beach line node. key_type new_node(*it_first, *it_second); // Update the output. edge_type* edge = output->_insert_new_edge(*it_first, *it_second).first; // Insert a new bisector into the beach line. beach_line_.insert(beach_line_.end(), std::pair<key_type, value_type>(new_node, value_type(edge))); // Update iterators. ++it_first; ++it_second; } } void deactivate_circle_event(value_type* value) { if (value->circle_event()) { value->circle_event()->deactivate(); value->circle_event(NULL); } } template <typename OUTPUT> void process_site_event(OUTPUT* output) { // Get next site event to process. site_event_type site_event = *site_event_iterator_; // Move site iterator. site_event_iterator_type last = site_event_iterator_ + 1; // If a new site is an end point of some segment, // remove temporary nodes from the beach line data structure. if (!site_event.is_segment()) { while (!end_points_.empty() && end_points_.top().first == site_event.point0()) { beach_line_iterator b_it = end_points_.top().second; end_points_.pop(); beach_line_.erase(b_it); } } else { while (last != site_events_.end() && last->is_segment() && last->point0() == site_event.point0()) ++last; } // Find the node in the binary search tree with left arc // lying above the new site point. key_type new_key(*site_event_iterator_); beach_line_iterator right_it = beach_line_.lower_bound(new_key); for (; site_event_iterator_ != last; ++site_event_iterator_) { site_event = *site_event_iterator_; beach_line_iterator left_it = right_it; // Do further processing depending on the above node position. // For any two neighboring nodes the second site of the first node // is the same as the first site of the second node. if (right_it == beach_line_.end()) { // The above arc corresponds to the second arc of the last node. // Move the iterator to the last node. --left_it; // Get the second site of the last node const site_event_type& site_arc = left_it->first.right_site(); // Insert new nodes into the beach line. Update the output. right_it = insert_new_arc( site_arc, site_arc, site_event, right_it, output); // Add a candidate circle to the circle event queue. // There could be only one new circle event formed by // a new bisector and the one on the left. activate_circle_event(left_it->first.left_site(), left_it->first.right_site(), site_event, right_it); } else if (right_it == beach_line_.begin()) { // The above arc corresponds to the first site of the first node. const site_event_type& site_arc = right_it->first.left_site(); // Insert new nodes into the beach line. Update the output. left_it = insert_new_arc( site_arc, site_arc, site_event, right_it, output); // If the site event is a segment, update its direction. if (site_event.is_segment()) { site_event.inverse(); } // Add a candidate circle to the circle event queue. // There could be only one new circle event formed by // a new bisector and the one on the right. activate_circle_event(site_event, right_it->first.left_site(), right_it->first.right_site(), right_it); right_it = left_it; } else { // The above arc corresponds neither to the first, // nor to the last site in the beach line. const site_event_type& site_arc2 = right_it->first.left_site(); const site_event_type& site3 = right_it->first.right_site(); // Remove the candidate circle from the event queue. deactivate_circle_event(&right_it->second); --left_it; const site_event_type& site_arc1 = left_it->first.right_site(); const site_event_type& site1 = left_it->first.left_site(); // Insert new nodes into the beach line. Update the output. beach_line_iterator new_node_it = insert_new_arc(site_arc1, site_arc2, site_event, right_it, output); // Add candidate circles to the circle event queue. // There could be up to two circle events formed by // a new bisector and the one on the left or right. activate_circle_event(site1, site_arc1, site_event, new_node_it); // If the site event is a segment, update its direction. if (site_event.is_segment()) { site_event.inverse(); } activate_circle_event(site_event, site_arc2, site3, right_it); right_it = new_node_it; } } } // In general case circle event is made of the three consecutive sites // that form two bisectors in the beach line data structure. // Let circle event sites be A, B, C, two bisectors that define // circle event are (A, B), (B, C). During circle event processing // we remove (A, B), (B, C) and insert (A, C). As beach line comparison // works correctly only if one of the nodes is a new one we remove // (B, C) bisector and change (A, B) bisector to the (A, C). That's // why we use const_cast there and take all the responsibility that // map data structure keeps correct ordering. template <typename OUTPUT> void process_circle_event(OUTPUT* output) { // Get the topmost circle event. const event_type& e = circle_events_.top(); const circle_event_type& circle_event = e.first; beach_line_iterator it_first = e.second; beach_line_iterator it_last = it_first; // Get the C site. site_event_type site3 = it_first->first.right_site(); // Get the half-edge corresponding to the second bisector - (B, C). edge_type* bisector2 = it_first->second.edge(); // Get the half-edge corresponding to the first bisector - (A, B). --it_first; edge_type* bisector1 = it_first->second.edge(); // Get the A site. site_event_type site1 = it_first->first.left_site(); if (!site1.is_segment() && site3.is_segment() && site3.point1() == site1.point0()) { site3.inverse(); } // Change the (A, B) bisector node to the (A, C) bisector node. const_cast<key_type&>(it_first->first).right_site(site3); // Insert the new bisector into the beach line. it_first->second.edge(output->_insert_new_edge( site1, site3, circle_event, bisector1, bisector2).first); // Remove the (B, C) bisector node from the beach line. beach_line_.erase(it_last); it_last = it_first; // Pop the topmost circle event from the event queue. circle_events_.pop(); // Check new triplets formed by the neighboring arcs // to the left for potential circle events. if (it_first != beach_line_.begin()) { deactivate_circle_event(&it_first->second); --it_first; const site_event_type& site_l1 = it_first->first.left_site(); activate_circle_event(site_l1, site1, site3, it_last); } // Check the new triplet formed by the neighboring arcs // to the right for potential circle events. ++it_last; if (it_last != beach_line_.end()) { deactivate_circle_event(&it_last->second); const site_event_type& site_r1 = it_last->first.right_site(); activate_circle_event(site1, site3, site_r1, it_last); } } // Insert new nodes into the beach line. Update the output. template <typename OUTPUT> beach_line_iterator insert_new_arc( const site_event_type& site_arc1, const site_event_type &site_arc2, const site_event_type& site_event, beach_line_iterator position, OUTPUT* output) { // Create two new bisectors with opposite directions. key_type new_left_node(site_arc1, site_event); key_type new_right_node(site_event, site_arc2); // Set correct orientation for the first site of the second node. if (site_event.is_segment()) { new_right_node.left_site().inverse(); } // Update the output. std::pair<edge_type*, edge_type*> edges = output->_insert_new_edge(site_arc2, site_event); position = beach_line_.insert(position, typename beach_line_type::value_type( new_right_node, value_type(edges.second))); if (site_event.is_segment()) { // Update the beach line with temporary bisector, that will // disappear after processing site event corresponding to the // second endpoint of the segment site. key_type new_node(site_event, site_event); new_node.right_site().inverse(); position = beach_line_.insert(position, typename beach_line_type::value_type(new_node, value_type(NULL))); // Update the data structure that holds temporary bisectors. end_points_.push(std::make_pair(site_event.point1(), position)); } position = beach_line_.insert(position, typename beach_line_type::value_type( new_left_node, value_type(edges.first))); return position; } // Add a new circle event to the event queue. // bisector_node corresponds to the (site2, site3) bisector. void activate_circle_event(const site_event_type& site1, const site_event_type& site2, const site_event_type& site3, beach_line_iterator bisector_node) { circle_event_type c_event; // Check if the three input sites create a circle event. if (circle_formation_predicate_(site1, site2, site3, c_event)) { // Add the new circle event to the circle events queue. // Update bisector's circle event iterator to point to the // new circle event in the circle event queue. event_type& e = circle_events_.push( std::pair<circle_event_type, beach_line_iterator>( c_event, bisector_node)); bisector_node->second.circle_event(&e.first); } } private: point_comparison_predicate point_comparison_; struct end_point_comparison { bool operator() (const end_point_type& end1, const end_point_type& end2) const { return point_comparison(end2.first, end1.first); } point_comparison_predicate point_comparison; }; std::vector<site_event_type> site_events_; site_event_iterator_type site_event_iterator_; std::priority_queue< end_point_type, std::vector<end_point_type>, end_point_comparison > end_points_; circle_event_queue_type circle_events_; beach_line_type beach_line_; circle_formation_predicate_type circle_formation_predicate_; std::size_t index_; // Disallow copy constructor and operator= voronoi_builder(const voronoi_builder&); void operator=(const voronoi_builder&); }; typedef voronoi_builder<detail::int32> default_voronoi_builder; } // polygon } // boost #endif // BOOST_POLYGON_VORONOI_BUILDER polygon_90_with_holes_data.hpp 0000644 00000007632 15125572616 0012514 0 ustar 00 /* 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_WITH_HOLES_DATA_HPP #define BOOST_POLYGON_POLYGON_90_WITH_HOLES_DATA_HPP namespace boost { namespace polygon{ #include "isotropy.hpp" #include "polygon_90_data.hpp" struct polygon_90_with_holes_concept; template <typename T> class polygon_90_with_holes_data { public: typedef polygon_90_with_holes_concept geometry_type; typedef T coordinate_type; typedef typename polygon_90_data<T>::iterator_type iterator_type; typedef typename polygon_90_data<T>::compact_iterator_type compact_iterator_type; typedef typename std::list<polygon_90_data<coordinate_type> >::const_iterator iterator_holes_type; typedef polygon_90_data<coordinate_type> hole_type; typedef typename coordinate_traits<T>::area_type area_type; typedef point_data<T> point_type; // default constructor of point does not initialize x and y inline polygon_90_with_holes_data() : self_(), holes_() {} //do nothing default constructor // initialize a polygon from x,y values, it is assumed that the first is an x // and that the input is a well behaved polygon template<class iT> inline polygon_90_with_holes_data& set(iT input_begin, iT input_end) { self_.set(input_begin, input_end); return *this; } // initialize a polygon from x,y values, it is assumed that the first is an x // and that the input is a well behaved polygon template<class iT> inline polygon_90_with_holes_data& set_compact(iT input_begin, iT input_end) { self_.set_compact(input_begin, input_end); return *this; } // initialize a polygon from x,y values, it is assumed that the first is an x // and that the input is a well behaved polygon template<class iT> inline polygon_90_with_holes_data& set_holes(iT input_begin, iT input_end) { holes_.clear(); //just in case there was some old data there for( ; input_begin != input_end; ++ input_begin) { holes_.push_back(hole_type()); holes_.back().set_compact((*input_begin).begin_compact(), (*input_begin).end_compact()); } return *this; } // copy constructor (since we have dynamic memory) inline polygon_90_with_holes_data(const polygon_90_with_holes_data& that) : self_(that.self_), holes_(that.holes_) {} // assignment operator (since we have dynamic memory do a deep copy) inline polygon_90_with_holes_data& operator=(const polygon_90_with_holes_data& that) { self_ = that.self_; holes_ = that.holes_; return *this; } template <typename T2> inline polygon_90_with_holes_data& operator=(const T2& rvalue); // get begin iterator, returns a pointer to a const coordinate_type inline const iterator_type begin() const { return self_.begin(); } // get end iterator, returns a pointer to a const coordinate_type inline const iterator_type end() const { return self_.end(); } // get begin iterator, returns a pointer to a const coordinate_type inline const compact_iterator_type begin_compact() const { return self_.begin_compact(); } // get end iterator, returns a pointer to a const coordinate_type inline const compact_iterator_type end_compact() const { return self_.end_compact(); } inline std::size_t size() const { return self_.size(); } // get begin iterator, returns a pointer to a const polygon inline const iterator_holes_type begin_holes() const { return holes_.begin(); } // get end iterator, returns a pointer to a const polygon inline const iterator_holes_type end_holes() const { return holes_.end(); } inline std::size_t size_holes() const { return holes_.size(); } private: polygon_90_data<coordinate_type> self_; std::list<hole_type> holes_; }; } } #endif polygon_90_set_data.hpp 0000644 00000126725 15125572616 0011147 0 ustar 00 /* 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 "transform.hpp" #include "interval_concept.hpp" #include "rectangle_concept.hpp" #include "segment_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 <typename ltype, typename rtype, typename op_type> class polygon_90_set_view; template <typename T> class polygon_90_set_data { public: typedef T coordinate_type; typedef std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > > value_type; typedef typename std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::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 <typename iT> inline polygon_90_set_data(orientation_2d, 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 <typename ltype, typename rtype, typename op_type> inline polygon_90_set_data(const polygon_90_set_view<ltype, rtype, op_type>& 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 <typename ltype, typename rtype, typename op_type> inline polygon_90_set_data& operator=(const polygon_90_set_view<ltype, rtype, op_type>& that); template <typename geometry_object> 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 <typename iT> 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<std::pair<point_data<coordinate_type>, point_data<coordinate_type> >, int>& edge, bool is_hole = false, orientation_2d = HORIZONTAL) { std::pair<coordinate_type, std::pair<coordinate_type, int> > 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 <typename geometry_type> inline void insert(const geometry_type& geometry_object, bool is_hole = false, orientation_2d = HORIZONTAL) { iterator_geometry_to_set<typename geometry_concept<geometry_type>::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<coordinate_type, std::pair<coordinate_type, int> >& 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<interval_data<coordinate_type>, int>& edge) { std::pair<coordinate_type, std::pair<coordinate_type, int> > 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 <typename output_container> inline void get(output_container& output) const { get_dispatch(output, typename geometry_concept<typename output_container::value_type>::type()); } template <typename output_container> inline void get(output_container& output, size_t vthreshold) const { get_dispatch(output, typename geometry_concept<typename output_container::value_type>::type(), vthreshold); } template <typename output_container> inline void get_polygons(output_container& output) const { get_dispatch(output, polygon_90_concept()); } template <typename output_container> inline void get_rectangles(output_container& output) const { clean(); form_rectangles(output, data_.begin(), data_.end(), orient_, rectangle_concept()); } template <typename output_container> inline void get_rectangles(output_container& output, orientation_2d slicing_orientation) const { if(slicing_orientation == orient_) { get_rectangles(output); } else { polygon_90_set_data<coordinate_type> 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<coordinate_type>& 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<boolean_op::BinaryNot>()); // return *this; // } // polygon_90_set_data<coordinate_type>& 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<boolean_op::BinaryXor>()); // return *this; // } // polygon_90_set_data<coordinate_type>& 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<boolean_op::BinaryAnd>()); // return *this; // } // polygon_90_set_data<coordinate_type>& operator|=(const polygon_90_set_data& that) { // insert(that); // return *this; // } void clean() const { sort(); if(dirty_) { boolean_op::default_arg_workaround<int>::applyBooleanOr(data_); dirty_ = false; } } void sort() const{ if(unsorted_) { polygon_sort(data_.begin(), data_.end()); unsorted_ = false; } } template <typename input_iterator_type> void set(input_iterator_type input_begin, input_iterator_type input_end, orientation_2d orient) { data_.clear(); reserve(std::distance(input_begin, input_end)); 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 <typename rectangle_type> bool extents(rectangle_type& extents_rectangle) const { clean(); if(data_.empty()) return false; if(orient_ == HORIZONTAL) set_points(extents_rectangle, point_data<coordinate_type>(data_[0].second.first, data_[0].first), point_data<coordinate_type>(data_[data_.size() - 1].second.first, data_[data_.size() - 1].first)); else set_points(extents_rectangle, point_data<coordinate_type>(data_[0].first, data_[0].second.first), point_data<coordinate_type>(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<coordinate_type>(data_[i].second.first, data_[i].first)); else encompass(extents_rectangle, point_data<coordinate_type>(data_[i].first, data_[i].second.first)); } return true; } polygon_90_set_data& bloat2(typename coordinate_traits<coordinate_type>::unsigned_area_type west_bloating, typename coordinate_traits<coordinate_type>::unsigned_area_type east_bloating, typename coordinate_traits<coordinate_type>::unsigned_area_type south_bloating, typename coordinate_traits<coordinate_type>::unsigned_area_type north_bloating) { std::vector<rectangle_data<coordinate_type> > rects; clean(); rects.reserve(data_.size() / 2); get(rects); rectangle_data<coordinate_type> convolutionRectangle(interval_data<coordinate_type>(-((coordinate_type)west_bloating), (coordinate_type)east_bloating), interval_data<coordinate_type>(-((coordinate_type)south_bloating), (coordinate_type)north_bloating)); for(typename std::vector<rectangle_data<coordinate_type> >::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<coordinate_type>& pt, const point_data<coordinate_type>& prev_pt, const point_data<coordinate_type>& current_pt, const point_data<coordinate_type>& 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<point_data<coordinate_type> >& poly, coordinate_type west_bloating, coordinate_type east_bloating, coordinate_type south_bloating, coordinate_type north_bloating) { point_data<coordinate_type> first_pt = poly[0]; point_data<coordinate_type> second_pt = poly[1]; point_data<coordinate_type> prev_pt = poly[0]; point_data<coordinate_type> current_pt = poly[1]; for(std::size_t i = 2; i < poly.size(); ++i) { point_data<coordinate_type> 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<coordinate_type> 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<point_data<coordinate_type> >& poly, coordinate_type west_shrinking, coordinate_type east_shrinking, coordinate_type south_shrinking, coordinate_type north_shrinking) { rectangle_data<coordinate_type> extents_rectangle; set_points(extents_rectangle, poly[0], poly[0]); point_data<coordinate_type> first_pt = poly[0]; point_data<coordinate_type> second_pt = poly[1]; point_data<coordinate_type> prev_pt = poly[0]; point_data<coordinate_type> current_pt = poly[1]; encompass(extents_rectangle, current_pt); for(std::size_t i = 2; i < poly.size(); ++i) { point_data<coordinate_type> 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<coordinate_type> 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<point_data<coordinate_type> >& poly) { bool found_colinear = true; while(found_colinear && poly.size() >= 4) { found_colinear = false; typename std::vector<point_data<coordinate_type> >::iterator itr = poly.begin(); itr += poly.size() - 1; //get last element position typename std::vector<point_data<coordinate_type> >::iterator itr2 = poly.begin(); typename std::vector<point_data<coordinate_type> >::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<coordinate_type>::unsigned_area_type west_bloating, typename coordinate_traits<coordinate_type>::unsigned_area_type east_bloating, typename coordinate_traits<coordinate_type>::unsigned_area_type south_bloating, typename coordinate_traits<coordinate_type>::unsigned_area_type north_bloating) { std::list<polygon_45_with_holes_data<coordinate_type> > polys; get(polys); clear(); for(typename std::list<polygon_45_with_holes_data<coordinate_type> >::iterator itr = polys.begin(); itr != polys.end(); ++itr) { //polygon_90_set_data<coordinate_type> psref; //psref.insert(view_as<polygon_90_concept>((*itr).self_)); //rectangle_data<coordinate_type> prerect; //psref.extents(prerect); resize_poly_up((*itr).self_.coords_, (coordinate_type)west_bloating, (coordinate_type)east_bloating, (coordinate_type)south_bloating, (coordinate_type)north_bloating); iterator_geometry_to_set<polygon_90_concept, view_of<polygon_90_concept, polygon_45_data<coordinate_type> > > begin_input(view_as<polygon_90_concept>((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE), end_input(view_as<polygon_90_concept>((*itr).self_), HIGH, orient_, false, true, COUNTERCLOCKWISE); insert(begin_input, end_input, orient_); //polygon_90_set_data<coordinate_type> pstest; //pstest.insert(view_as<polygon_90_concept>((*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<polygon_45_data<coordinate_type> >::iterator itrh = (*itr).holes_.begin(); itrh != (*itr).holes_.end(); ++itrh) { //rectangle_data<coordinate_type> rect; //psref.extents(rect); //polygon_90_set_data<coordinate_type> psrefhole; //psrefhole.insert(prerect); //psrefhole.insert(view_as<polygon_90_concept>(*itrh), true); //polygon_45_data<coordinate_type> testpoly(*itrh); if(resize_poly_down((*itrh).coords_,(coordinate_type)west_bloating, (coordinate_type)east_bloating, (coordinate_type)south_bloating, (coordinate_type)north_bloating)) { iterator_geometry_to_set<polygon_90_concept, view_of<polygon_90_concept, polygon_45_data<coordinate_type> > > begin_input2(view_as<polygon_90_concept>(*itrh), LOW, orient_, true, true), end_input2(view_as<polygon_90_concept>(*itrh), HIGH, orient_, true, true); insert(begin_input2, end_input2, orient_); //polygon_90_set_data<coordinate_type> pstesthole; //pstesthole.insert(rect); //iterator_geometry_to_set<polygon_90_concept, view_of<polygon_90_concept, polygon_45_data<coordinate_type> > > // begin_input2(view_as<polygon_90_concept>(*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<coordinate_type> c(psrefhole); // c.clean(); // polygon_90_set_data<coordinate_type> a(pstesthole); // polygon_90_set_data<coordinate_type> 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<coordinate_type>::unsigned_area_type west_shrinking, typename coordinate_traits<coordinate_type>::unsigned_area_type east_shrinking, typename coordinate_traits<coordinate_type>::unsigned_area_type south_shrinking, typename coordinate_traits<coordinate_type>::unsigned_area_type north_shrinking) { std::list<polygon_45_with_holes_data<coordinate_type> > polys; get(polys); clear(); for(typename std::list<polygon_45_with_holes_data<coordinate_type> >::iterator itr = polys.begin(); itr != polys.end(); ++itr) { //polygon_90_set_data<coordinate_type> psref; //psref.insert(view_as<polygon_90_concept>((*itr).self_)); //rectangle_data<coordinate_type> prerect; //psref.extents(prerect); //polygon_45_data<coordinate_type> testpoly((*itr).self_); if(resize_poly_down((*itr).self_.coords_, -(coordinate_type)west_shrinking, -(coordinate_type)east_shrinking, -(coordinate_type)south_shrinking, -(coordinate_type)north_shrinking)) { iterator_geometry_to_set<polygon_90_concept, view_of<polygon_90_concept, polygon_45_data<coordinate_type> > > begin_input(view_as<polygon_90_concept>((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE), end_input(view_as<polygon_90_concept>((*itr).self_), HIGH, orient_, false, true, COUNTERCLOCKWISE); insert(begin_input, end_input, orient_); //iterator_geometry_to_set<polygon_90_concept, view_of<polygon_90_concept, polygon_45_data<coordinate_type> > > // begin_input2(view_as<polygon_90_concept>((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE); //polygon_90_set_data<coordinate_type> 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<polygon_45_data<coordinate_type> >::iterator itrh = (*itr).holes_.begin(); itrh != (*itr).holes_.end(); ++itrh) { //rectangle_data<coordinate_type> rect; //psref.extents(rect); //polygon_90_set_data<coordinate_type> psrefhole; //psrefhole.insert(prerect); //psrefhole.insert(view_as<polygon_90_concept>(*itrh), true); //polygon_45_data<coordinate_type> testpoly(*itrh); resize_poly_up((*itrh).coords_, -(coordinate_type)west_shrinking, -(coordinate_type)east_shrinking, -(coordinate_type)south_shrinking, -(coordinate_type)north_shrinking); iterator_geometry_to_set<polygon_90_concept, view_of<polygon_90_concept, polygon_45_data<coordinate_type> > > begin_input2(view_as<polygon_90_concept>(*itrh), LOW, orient_, true, true), end_input2(view_as<polygon_90_concept>(*itrh), HIGH, orient_, true, true); insert(begin_input2, end_input2, orient_); //polygon_90_set_data<coordinate_type> pstesthole; //pstesthole.insert(rect); //iterator_geometry_to_set<polygon_90_concept, view_of<polygon_90_concept, polygon_45_data<coordinate_type> > > // begin_input2(view_as<polygon_90_concept>(*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<coordinate_type> c(psrefhole); // c.clean(); // polygon_90_set_data<coordinate_type> a(pstesthole); // polygon_90_set_data<coordinate_type> 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<coordinate_type>::unsigned_area_type west_shrinking, typename coordinate_traits<coordinate_type>::unsigned_area_type east_shrinking, typename coordinate_traits<coordinate_type>::unsigned_area_type south_shrinking, typename coordinate_traits<coordinate_type>::unsigned_area_type north_shrinking) { rectangle_data<coordinate_type> 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<rectangle_data<coordinate_type> > 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<coordinate_type> convolutionRectangle(interval_data<coordinate_type>(-((coordinate_type)east_shrinking), (coordinate_type)west_shrinking), interval_data<coordinate_type>(-((coordinate_type)north_shrinking), (coordinate_type)south_shrinking)); for(typename std::vector<rectangle_data<coordinate_type> >::iterator itr = rects.begin(); itr != rects.end(); ++itr) { rectangle_data<coordinate_type>& 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<coordinate_type>::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<coordinate_type>::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<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::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 <typename transformation_type> 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<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::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<coordinate_type>::unsigned_area_type factor) { for(typename std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::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<coordinate_type>::unsigned_area_type factor) { typedef typename coordinate_traits<coordinate_type>::coordinate_distance dt; for(typename std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::iterator itr = data_.begin(); itr != data_.end(); ++itr) { (*itr).first = scaling_policy<coordinate_type>::round((dt)((*itr).first) / (dt)factor); (*itr).second.first = scaling_policy<coordinate_type>::round((dt)((*itr).second.first) / (dt)factor); } unsorted_ = true; //scaling down can make coordinates equal that were not previously equal return *this; } template <typename scaling_type> polygon_90_set_data& scale(const anisotropic_scale_factor<scaling_type>& scaling) { for(typename std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::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 <typename scaling_type> polygon_90_set_data& scale_with(const scaling_type& scaling) { for(typename std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::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_type>::coordinate_distance dt; for(typename std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::iterator itr = data_.begin(); itr != data_.end(); ++itr) { (*itr).first = scaling_policy<coordinate_type>::round((dt)((*itr).first) * (dt)factor); (*itr).second.first = scaling_policy<coordinate_type>::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<boolean_op::UnaryCount>::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<coordinate_type> ivl((std::numeric_limits<coordinate_type>::min)(), (std::numeric_limits<coordinate_type>::max)()); rectangle_data<coordinate_type> 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<Unit>::TouchSetData tsd; touch_90_operation<Unit>::populateTouchSetData(tsd, that.data_, 0); std::vector<polygon_90_data<Unit> > polys; get(polys); std::vector<std::set<int> > graph(polys.size()+1, std::set<int>()); for(std::size_t i = 0; i < polys.size(); ++i){ polygon_90_set_data<Unit> psTmp(that.orient_); psTmp.insert(polys[i]); psTmp.clean(); touch_90_operation<Unit>::populateTouchSetData(tsd, psTmp.data_, i+1); } touch_90_operation<Unit>::performTouch(graph, tsd); clear(); for(std::set<int>::iterator itr = graph[0].begin(); itr != graph[0].end(); ++itr){ insert(polys[(*itr)-1]); } dirty_ = false; return *this; } template <class T2, typename iterator_type_1, typename iterator_type_2> 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 <typename output_container> void get_dispatch(output_container& output, rectangle_concept ) const { clean(); form_rectangles(output, data_.begin(), data_.end(), orient_, rectangle_concept()); } template <typename output_container> void get_dispatch(output_container& output, polygon_90_concept tag) const { get_fracture(output, true, tag); } template <typename output_container> void get_dispatch(output_container& output, polygon_90_concept tag, size_t vthreshold) const { get_fracture(output, true, tag, vthreshold); } template <typename output_container> void get_dispatch(output_container& output, polygon_90_with_holes_concept tag) const { get_fracture(output, false, tag); } template <typename output_container> void get_dispatch(output_container& output, polygon_90_with_holes_concept tag, size_t vthreshold) const { get_fracture(output, false, tag, vthreshold); } template <typename output_container> void get_dispatch(output_container& output, polygon_45_concept tag) const { get_fracture(output, true, tag); } template <typename output_container> void get_dispatch(output_container& output, polygon_45_with_holes_concept tag) const { get_fracture(output, false, tag); } template <typename output_container> void get_dispatch(output_container& output, polygon_concept tag) const { get_fracture(output, true, tag); } template <typename output_container> void get_dispatch(output_container& output, polygon_with_holes_concept tag) const { get_fracture(output, false, tag); } template <typename output_container, typename concept_type> 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 <typename output_container, typename concept_type> void get_fracture(output_container& container, bool fracture_holes, concept_type tag, size_t vthreshold) const { clean(); ::boost::polygon::get_polygons(container, data_.begin(), data_.end(), orient_, fracture_holes, tag, vthreshold); } }; template <typename coordinate_type> polygon_90_set_data<coordinate_type>& polygon_90_set_data<coordinate_type>::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 <typename coordinate_type, typename property_type> class property_merge_90 { private: std::vector<std::pair<property_merge_point<coordinate_type>, std::pair<property_type, int> > > 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<coordinate_type>& ps, const property_type& property) { merge_scanline<coordinate_type, property_type, polygon_90_set_data<coordinate_type> >:: populate_property_merge_data(pmd_, ps.begin(), ps.end(), property, ps.orient()); } template <class GeoObjT> inline void insert(const GeoObjT& geoObj, const property_type& property) { polygon_90_set_data<coordinate_type> 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<std::set<property_type>, polygon_90_set_data<coordiante_type> > or // T = std::map<std::vector<property_type>, polygon_90_set_data<coordiante_type> > template <typename ResultType> inline void merge(ResultType& result) { merge_scanline<coordinate_type, property_type, polygon_90_set_data<coordinate_type>, 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 <typename coordinate_type> class connectivity_extraction_90 { private: typedef typename touch_90_operation<coordinate_type>::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<coordinate_type>& ps) { ps.clean(); touch_90_operation<coordinate_type>::populateTouchSetData(tsd_, ps.begin(), ps.end(), nodeCount_); return nodeCount_++; } template <class GeoObjT> inline unsigned int insert(const GeoObjT& geoObj) { polygon_90_set_data<coordinate_type> 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 <class GraphT> inline void extract(GraphT& graph) { touch_90_operation<coordinate_type>::performTouch(graph, tsd_); } }; } } #endif polygon_45_set_data.hpp 0000644 00000230772 15125572616 0011145 0 ustar 00 /* 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_45_SET_DATA_HPP #define BOOST_POLYGON_POLYGON_45_SET_DATA_HPP #include "polygon_90_set_data.hpp" #include "detail/boolean_op_45.hpp" #include "detail/polygon_45_formation.hpp" #include "detail/polygon_45_touch.hpp" #include "detail/property_merge_45.hpp" namespace boost { namespace polygon{ enum RoundingOption { CLOSEST = 0, OVERSIZE = 1, UNDERSIZE = 2, SQRT2 = 3, SQRT1OVER2 = 4 }; enum CornerOption { INTERSECTION = 0, ORTHOGONAL = 1, UNFILLED = 2 }; template <typename ltype, typename rtype, int op_type> class polygon_45_set_view; struct polygon_45_set_concept {}; template <typename Unit> class polygon_45_set_data { public: typedef typename polygon_45_formation<Unit>::Vertex45Compact Vertex45Compact; typedef std::vector<Vertex45Compact> Polygon45VertexData; typedef Unit coordinate_type; typedef Polygon45VertexData value_type; typedef typename value_type::const_iterator iterator_type; typedef polygon_45_set_data operator_arg_type; // default constructor inline polygon_45_set_data() : error_data_(), data_(), dirty_(false), unsorted_(false), is_manhattan_(true) {} // constructor from a geometry object template <typename geometry_type> inline polygon_45_set_data(const geometry_type& that) : error_data_(), data_(), dirty_(false), unsorted_(false), is_manhattan_(true) { insert(that); } // copy constructor inline polygon_45_set_data(const polygon_45_set_data& that) : error_data_(that.error_data_), data_(that.data_), dirty_(that.dirty_), unsorted_(that.unsorted_), is_manhattan_(that.is_manhattan_) {} template <typename ltype, typename rtype, int op_type> inline polygon_45_set_data(const polygon_45_set_view<ltype, rtype, op_type>& that) : error_data_(), data_(), dirty_(false), unsorted_(false), is_manhattan_(true) { (*this) = that.value(); } // destructor inline ~polygon_45_set_data() {} // assignement operator inline polygon_45_set_data& operator=(const polygon_45_set_data& that) { if(this == &that) return *this; error_data_ = that.error_data_; data_ = that.data_; dirty_ = that.dirty_; unsorted_ = that.unsorted_; is_manhattan_ = that.is_manhattan_; return *this; } template <typename ltype, typename rtype, int op_type> inline polygon_45_set_data& operator=(const polygon_45_set_view<ltype, rtype, op_type>& that) { (*this) = that.value(); return *this; } template <typename geometry_object> inline polygon_45_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, bool is_hole = false) { if(input_begin == input_end || (!data_.empty() && &(*input_begin) == &(*(data_.begin())))) return; dirty_ = true; unsorted_ = true; while(input_begin != input_end) { insert(*input_begin, is_hole); ++input_begin; } } // insert iterator range template <typename iT> inline void insert(iT input_begin, iT input_end, bool is_hole = false) { if(input_begin == input_end) return; dirty_ = true; unsorted_ = true; while(input_begin != input_end) { insert(*input_begin, is_hole); ++input_begin; } } inline void insert(const polygon_45_set_data& polygon_set, bool is_hole = false); template <typename coord_type> inline void insert(const polygon_45_set_data<coord_type>& polygon_set, bool is_hole = false); template <typename geometry_type> inline void insert(const geometry_type& geometry_object, bool is_hole = false) { insert_dispatch(geometry_object, is_hole, typename geometry_concept<geometry_type>::type()); } inline void insert_clean(const Vertex45Compact& vertex_45, bool is_hole = false) { if(vertex_45.count.is_45()) is_manhattan_ = false; data_.push_back(vertex_45); if(is_hole) data_.back().count.invert(); } inline void insert(const Vertex45Compact& vertex_45, bool is_hole = false) { dirty_ = true; unsorted_ = true; insert_clean(vertex_45, is_hole); } template <typename coordinate_type_2> inline void insert(const polygon_90_set_data<coordinate_type_2>& polygon_set, bool is_hole = false) { if(polygon_set.orient() == VERTICAL) { for(typename polygon_90_set_data<coordinate_type_2>::iterator_type itr = polygon_set.begin(); itr != polygon_set.end(); ++itr) { Vertex45Compact vertex_45(point_data<Unit>((*itr).first, (*itr).second.first), 2, (*itr).second.second); vertex_45.count[1] = (*itr).second.second; if(is_hole) vertex_45.count[1] *= - 1; insert_clean(vertex_45, is_hole); } } else { for(typename polygon_90_set_data<coordinate_type_2>::iterator_type itr = polygon_set.begin(); itr != polygon_set.end(); ++itr) { Vertex45Compact vertex_45(point_data<Unit>((*itr).second.first, (*itr).first), 2, (*itr).second.second); vertex_45.count[1] = (*itr).second.second; if(is_hole) vertex_45.count[1] *= - 1; insert_clean(vertex_45, is_hole); } } dirty_ = true; unsorted_ = true; } template <typename output_container> inline void get(output_container& output) const { get_dispatch(output, typename geometry_concept<typename output_container::value_type>::type()); } inline bool has_error_data() const { return !error_data_.empty(); } inline std::size_t error_count() const { return error_data_.size() / 4; } inline void get_error_data(polygon_45_set_data& p) const { p.data_.insert(p.data_.end(), error_data_.begin(), error_data_.end()); } // equivalence operator inline bool operator==(const polygon_45_set_data& p) const { clean(); p.clean(); return data_ == p.data_; } // inequivalence operator inline bool operator!=(const polygon_45_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_45_set_data inline void clear() { data_.clear(); error_data_.clear(); dirty_ = unsorted_ = false; is_manhattan_ = true; } // find out if Polygon set is empty inline bool empty() const { 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_; } // find out if Polygon set is clean inline bool is_manhattan() const { return is_manhattan_; } bool clean() const; void sort() const{ if(unsorted_) { polygon_sort(data_.begin(), data_.end()); unsorted_ = false; } } template <typename input_iterator_type> void set(input_iterator_type input_begin, input_iterator_type input_end) { data_.clear(); reserve(std::distance(input_begin, input_end)); insert(input_begin, input_end); dirty_ = true; unsorted_ = true; } void set_clean(const value_type& value) { data_ = value; dirty_ = false; unsorted_ = false; } void set(const value_type& value) { data_ = value; dirty_ = true; unsorted_ = true; } // append to the container cT with polygons (holes will be fractured vertically) template <class cT> void get_polygons(cT& container) const { get_dispatch(container, polygon_45_concept()); } // append to the container cT with PolygonWithHoles objects template <class cT> void get_polygons_with_holes(cT& container) const { get_dispatch(container, polygon_45_with_holes_concept()); } // append to the container cT with polygons of three or four verticies // slicing orientation is vertical template <class cT> void get_trapezoids(cT& container) const { clean(); typename polygon_45_formation<Unit>::Polygon45Tiling pf; //std::cout << "FORMING POLYGONS\n"; pf.scan(container, data_.begin(), data_.end()); //std::cout << "DONE FORMING POLYGONS\n"; } // append to the container cT with polygons of three or four verticies template <class cT> void get_trapezoids(cT& container, orientation_2d slicing_orientation) const { if(slicing_orientation == VERTICAL) { get_trapezoids(container); } else { polygon_45_set_data<Unit> ps(*this); ps.transform(axis_transformation(axis_transformation::SWAP_XY)); cT result; ps.get_trapezoids(result); for(typename cT::iterator itr = result.begin(); itr != result.end(); ++itr) { ::boost::polygon::transform(*itr, axis_transformation(axis_transformation::SWAP_XY)); } container.insert(container.end(), result.begin(), result.end()); } } // insert vertex sequence template <class iT> void insert_vertex_sequence(iT begin_vertex, iT end_vertex, direction_1d winding, bool is_hole = false); // get the external boundary rectangle template <typename rectangle_type> bool extents(rectangle_type& rect) const; // snap verticies of set to even,even or odd,odd coordinates void snap() const; // |= &= += *= -= ^= binary operators polygon_45_set_data& operator|=(const polygon_45_set_data& b); polygon_45_set_data& operator&=(const polygon_45_set_data& b); polygon_45_set_data& operator+=(const polygon_45_set_data& b); polygon_45_set_data& operator*=(const polygon_45_set_data& b); polygon_45_set_data& operator-=(const polygon_45_set_data& b); polygon_45_set_data& operator^=(const polygon_45_set_data& b); // resizing operations polygon_45_set_data& operator+=(Unit delta); polygon_45_set_data& operator-=(Unit delta); // shrink the Polygon45Set by shrinking polygon_45_set_data& resize(coordinate_type resizing, RoundingOption rounding = CLOSEST, CornerOption corner = INTERSECTION); // transform set template <typename transformation_type> polygon_45_set_data& transform(const transformation_type& tr); // scale set polygon_45_set_data& scale_up(typename coordinate_traits<Unit>::unsigned_area_type factor); polygon_45_set_data& scale_down(typename coordinate_traits<Unit>::unsigned_area_type factor); polygon_45_set_data& scale(double scaling); // self_intersect polygon_45_set_data& self_intersect() { sort(); applyAdaptiveUnary_<1>(); //1 = AND dirty_ = false; return *this; } // self_xor polygon_45_set_data& self_xor() { sort(); applyAdaptiveUnary_<3>(); //3 = XOR dirty_ = false; return *this; } // accumulate the bloated polygon template <typename geometry_type> polygon_45_set_data& insert_with_resize(const geometry_type& poly, coordinate_type resizing, RoundingOption rounding = CLOSEST, CornerOption corner = INTERSECTION, bool hole = false) { return insert_with_resize_dispatch(poly, resizing, rounding, corner, hole, typename geometry_concept<geometry_type>::type()); } private: mutable value_type error_data_; mutable value_type data_; mutable bool dirty_; mutable bool unsorted_; mutable bool is_manhattan_; private: //functions template <typename output_container> void get_dispatch(output_container& output, polygon_45_concept tag) const { get_fracture(output, true, tag); } template <typename output_container> void get_dispatch(output_container& output, polygon_45_with_holes_concept tag) const { get_fracture(output, false, tag); } template <typename output_container> void get_dispatch(output_container& output, polygon_concept tag) const { get_fracture(output, true, tag); } template <typename output_container> void get_dispatch(output_container& output, polygon_with_holes_concept tag) const { get_fracture(output, false, tag); } template <typename output_container, typename concept_type> void get_fracture(output_container& container, bool fracture_holes, concept_type ) const { clean(); typename polygon_45_formation<Unit>::Polygon45Formation pf(fracture_holes); //std::cout << "FORMING POLYGONS\n"; pf.scan(container, data_.begin(), data_.end()); } template <typename geometry_type> void insert_dispatch(const geometry_type& geometry_object, bool is_hole, undefined_concept) { insert(geometry_object.begin(), geometry_object.end(), is_hole); } template <typename geometry_type> void insert_dispatch(const geometry_type& geometry_object, bool is_hole, rectangle_concept tag); template <typename geometry_type> void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_90_concept ) { insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole); } template <typename geometry_type> void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_90_with_holes_concept ) { insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole); for(typename polygon_with_holes_traits<geometry_type>::iterator_holes_type itr = begin_holes(geometry_object); itr != end_holes(geometry_object); ++itr) { insert_vertex_sequence(begin_points(*itr), end_points(*itr), winding(*itr), !is_hole); } } template <typename geometry_type> void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_45_concept ) { insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole); } template <typename geometry_type> void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_45_with_holes_concept ) { insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole); for(typename polygon_with_holes_traits<geometry_type>::iterator_holes_type itr = begin_holes(geometry_object); itr != end_holes(geometry_object); ++itr) { insert_vertex_sequence(begin_points(*itr), end_points(*itr), winding(*itr), !is_hole); } } template <typename geometry_type> void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_45_set_concept ) { polygon_45_set_data ps; assign(ps, geometry_object); insert(ps, is_hole); } template <typename geometry_type> void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_90_set_concept ) { std::list<polygon_90_data<coordinate_type> > pl; assign(pl, geometry_object); insert(pl.begin(), pl.end(), is_hole); } void insert_vertex_half_edge_45_pair(const point_data<Unit>& pt1, point_data<Unit>& pt2, const point_data<Unit>& pt3, direction_1d wdir); template <typename geometry_type> polygon_45_set_data& insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, RoundingOption rounding, CornerOption corner, bool hole, polygon_45_concept tag); // accumulate the bloated polygon with holes template <typename geometry_type> polygon_45_set_data& insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, RoundingOption rounding, CornerOption corner, bool hole, polygon_45_with_holes_concept tag); static void snap_vertex_45(Vertex45Compact& vertex); public: template <int op> void applyAdaptiveBoolean_(const polygon_45_set_data& rvalue) const; template <int op> void applyAdaptiveBoolean_(polygon_45_set_data& result, const polygon_45_set_data& rvalue) const; template <int op> void applyAdaptiveUnary_() const; }; template <typename T> struct geometry_concept<polygon_45_set_data<T> > { typedef polygon_45_set_concept type; }; template <typename iT, typename T> void scale_up_vertex_45_compact_range(iT beginr, iT endr, T factor) { for( ; beginr != endr; ++beginr) { scale_up((*beginr).pt, factor); } } template <typename iT, typename T> void scale_down_vertex_45_compact_range_blindly(iT beginr, iT endr, T factor) { for( ; beginr != endr; ++beginr) { scale_down((*beginr).pt, factor); } } template <typename Unit> inline std::pair<int, int> characterizeEdge45(const point_data<Unit>& pt1, const point_data<Unit>& pt2) { std::pair<int, int> retval(0, 1); if(pt1.x() == pt2.x()) { retval.first = 3; retval.second = -1; return retval; } //retval.second = pt1.x() < pt2.x() ? -1 : 1; retval.second = 1; if(pt1.y() == pt2.y()) { retval.first = 1; } else if(pt1.x() < pt2.x()) { if(pt1.y() < pt2.y()) { retval.first = 2; } else { retval.first = 0; } } else { if(pt1.y() < pt2.y()) { retval.first = 0; } else { retval.first = 2; } } return retval; } template <typename cT, typename pT> bool insert_vertex_half_edge_45_pair_into_vector(cT& output, const pT& pt1, pT& pt2, const pT& pt3, direction_1d wdir) { int multiplier = wdir == LOW ? -1 : 1; typename cT::value_type vertex(pt2, 0, 0); //std::cout << pt1 << " " << pt2 << " " << pt3 << std::endl; std::pair<int, int> check; check = characterizeEdge45(pt1, pt2); //std::cout << "index " << check.first << " " << check.second * -multiplier << std::endl; vertex.count[check.first] += check.second * -multiplier; check = characterizeEdge45(pt2, pt3); //std::cout << "index " << check.first << " " << check.second * multiplier << std::endl; vertex.count[check.first] += check.second * multiplier; output.push_back(vertex); return vertex.count.is_45(); } template <typename Unit> inline void polygon_45_set_data<Unit>::insert_vertex_half_edge_45_pair(const point_data<Unit>& pt1, point_data<Unit>& pt2, const point_data<Unit>& pt3, direction_1d wdir) { if(insert_vertex_half_edge_45_pair_into_vector(data_, pt1, pt2, pt3, wdir)) is_manhattan_ = false; } template <typename Unit> template <class iT> inline void polygon_45_set_data<Unit>::insert_vertex_sequence(iT begin_vertex, iT end_vertex, direction_1d winding, bool is_hole) { if(begin_vertex == end_vertex) return; if(is_hole) winding = winding.backward(); iT itr = begin_vertex; if(itr == end_vertex) return; point_data<Unit> firstPt = *itr; ++itr; point_data<Unit> secondPt(firstPt); //skip any duplicate points do { if(itr == end_vertex) return; secondPt = *itr; ++itr; } while(secondPt == firstPt); point_data<Unit> prevPt = secondPt; point_data<Unit> prevPrevPt = firstPt; while(itr != end_vertex) { point_data<Unit> pt = *itr; //skip any duplicate points if(pt == prevPt) { ++itr; continue; } //operate on the three points insert_vertex_half_edge_45_pair(prevPrevPt, prevPt, pt, winding); prevPrevPt = prevPt; prevPt = pt; ++itr; } if(prevPt != firstPt) { insert_vertex_half_edge_45_pair(prevPrevPt, prevPt, firstPt, winding); insert_vertex_half_edge_45_pair(prevPt, firstPt, secondPt, winding); } else { insert_vertex_half_edge_45_pair(prevPrevPt, firstPt, secondPt, winding); } dirty_ = true; unsorted_ = true; } // insert polygon set template <typename Unit> inline void polygon_45_set_data<Unit>::insert(const polygon_45_set_data<Unit>& polygon_set, bool is_hole) { std::size_t count = data_.size(); data_.insert(data_.end(), polygon_set.data_.begin(), polygon_set.data_.end()); error_data_.insert(error_data_.end(), polygon_set.error_data_.begin(), polygon_set.error_data_.end()); if(is_hole) { for(std::size_t i = count; i < data_.size(); ++i) { data_[i].count = data_[i].count.invert(); } } dirty_ = true; unsorted_ = true; if(polygon_set.is_manhattan_ == false) is_manhattan_ = false; return; } // insert polygon set template <typename Unit> template <typename coord_type> inline void polygon_45_set_data<Unit>::insert(const polygon_45_set_data<coord_type>& polygon_set, bool is_hole) { std::size_t count = data_.size(); for(typename polygon_45_set_data<coord_type>::iterator_type itr = polygon_set.begin(); itr != polygon_set.end(); ++itr) { const typename polygon_45_set_data<coord_type>::Vertex45Compact& v = *itr; typename polygon_45_set_data<Unit>::Vertex45Compact v2; v2.pt.x(static_cast<Unit>(v.pt.x())); v2.pt.y(static_cast<Unit>(v.pt.y())); v2.count = typename polygon_45_formation<Unit>::Vertex45Count(v.count[0], v.count[1], v.count[2], v.count[3]); data_.push_back(v2); } polygon_45_set_data<coord_type> tmp; polygon_set.get_error_data(tmp); for(typename polygon_45_set_data<coord_type>::iterator_type itr = tmp.begin(); itr != tmp.end(); ++itr) { const typename polygon_45_set_data<coord_type>::Vertex45Compact& v = *itr; typename polygon_45_set_data<Unit>::Vertex45Compact v2; v2.pt.x(static_cast<Unit>(v.pt.x())); v2.pt.y(static_cast<Unit>(v.pt.y())); v2.count = typename polygon_45_formation<Unit>::Vertex45Count(v.count[0], v.count[1], v.count[2], v.count[3]); error_data_.push_back(v2); } if(is_hole) { for(std::size_t i = count; i < data_.size(); ++i) { data_[i].count = data_[i].count.invert(); } } dirty_ = true; unsorted_ = true; if(polygon_set.is_manhattan() == false) is_manhattan_ = false; return; } template <typename cT, typename rT> void insert_rectangle_into_vector_45(cT& output, const rT& rect, bool is_hole) { point_data<typename rectangle_traits<rT>::coordinate_type> llpt = ll(rect), lrpt = lr(rect), ulpt = ul(rect), urpt = ur(rect); direction_1d dir = COUNTERCLOCKWISE; if(is_hole) dir = CLOCKWISE; insert_vertex_half_edge_45_pair_into_vector(output, llpt, lrpt, urpt, dir); insert_vertex_half_edge_45_pair_into_vector(output, lrpt, urpt, ulpt, dir); insert_vertex_half_edge_45_pair_into_vector(output, urpt, ulpt, llpt, dir); insert_vertex_half_edge_45_pair_into_vector(output, ulpt, llpt, lrpt, dir); } template <typename Unit> template <typename geometry_type> inline void polygon_45_set_data<Unit>::insert_dispatch(const geometry_type& geometry_object, bool is_hole, rectangle_concept ) { dirty_ = true; unsorted_ = true; insert_rectangle_into_vector_45(data_, geometry_object, is_hole); } // get the external boundary rectangle template <typename Unit> template <typename rectangle_type> inline bool polygon_45_set_data<Unit>::extents(rectangle_type& rect) const{ clean(); if(empty()) { return false; } Unit low = (std::numeric_limits<Unit>::max)(); Unit high = (std::numeric_limits<Unit>::min)(); interval_data<Unit> xivl(low, high); interval_data<Unit> yivl(low, high); for(typename value_type::const_iterator itr = data_.begin(); itr != data_.end(); ++ itr) { if((*itr).pt.x() > xivl.get(HIGH)) xivl.set(HIGH, (*itr).pt.x()); if((*itr).pt.x() < xivl.get(LOW)) xivl.set(LOW, (*itr).pt.x()); if((*itr).pt.y() > yivl.get(HIGH)) yivl.set(HIGH, (*itr).pt.y()); if((*itr).pt.y() < yivl.get(LOW)) yivl.set(LOW, (*itr).pt.y()); } rect = construct<rectangle_type>(xivl, yivl); return true; } //this function snaps the vertex and two half edges //to be both even or both odd coordinate values if one of the edges is 45 //and throws an excpetion if an edge is non-manhattan, non-45. template <typename Unit> inline void polygon_45_set_data<Unit>::snap_vertex_45(typename polygon_45_set_data<Unit>::Vertex45Compact& vertex) { bool plus45 = vertex.count[2] != 0; bool minus45 = vertex.count[0] != 0; if(plus45 || minus45) { if(local_abs(vertex.pt.x()) % 2 != local_abs(vertex.pt.y()) % 2) { if(vertex.count[1] != 0 || (plus45 && minus45)) { //move right vertex.pt.x(vertex.pt.x() + 1); } else { //assert that vertex.count[3] != 0 Unit modifier = plus45 ? -1 : 1; vertex.pt.y(vertex.pt.y() + modifier); } } } } template <typename Unit> inline void polygon_45_set_data<Unit>::snap() const { for(typename value_type::iterator itr = data_.begin(); itr != data_.end(); ++itr) { snap_vertex_45(*itr); } } // |= &= += *= -= ^= binary operators template <typename Unit> inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator|=(const polygon_45_set_data<Unit>& b) { insert(b); return *this; } template <typename Unit> inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator&=(const polygon_45_set_data<Unit>& b) { //b.sort(); //sort(); applyAdaptiveBoolean_<1>(b); dirty_ = false; unsorted_ = false; return *this; } template <typename Unit> inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator+=(const polygon_45_set_data<Unit>& b) { return (*this) |= b; } template <typename Unit> inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator*=(const polygon_45_set_data<Unit>& b) { return (*this) &= b; } template <typename Unit> inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator-=(const polygon_45_set_data<Unit>& b) { //b.sort(); //sort(); applyAdaptiveBoolean_<2>(b); dirty_ = false; unsorted_ = false; return *this; } template <typename Unit> inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator^=(const polygon_45_set_data<Unit>& b) { //b.sort(); //sort(); applyAdaptiveBoolean_<3>(b); dirty_ = false; unsorted_ = false; return *this; } template <typename Unit> inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator+=(Unit delta) { return resize(delta); } template <typename Unit> inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator-=(Unit delta) { return (*this) += -delta; } template <typename Unit> inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::resize(Unit resizing, RoundingOption rounding, CornerOption corner) { if(resizing == 0) return *this; std::list<polygon_45_with_holes_data<Unit> > pl; get_polygons_with_holes(pl); clear(); for(typename std::list<polygon_45_with_holes_data<Unit> >::iterator itr = pl.begin(); itr != pl.end(); ++itr) { insert_with_resize(*itr, resizing, rounding, corner); } clean(); //perterb 45 edges to prevent non-integer intersection errors upon boolean op //snap(); return *this; } //distance is assumed to be positive inline int roundClosest(double distance) { int f = (int)distance; if(distance - (double)f < 0.5) return f; return f+1; } //distance is assumed to be positive template <typename Unit> inline Unit roundWithOptions(double distance, RoundingOption rounding) { if(rounding == CLOSEST) { return roundClosest(distance); } else if(rounding == OVERSIZE) { return (Unit)distance + 1; } else { //UNDERSIZE return (Unit)distance; } } // 0 is east, 1 is northeast, 2 is north, 3 is northwest, 4 is west, 5 is southwest, 6 is south // 7 is southwest template <typename Unit> inline point_data<Unit> bloatVertexInDirWithOptions(const point_data<Unit>& point, unsigned int dir, Unit bloating, RoundingOption rounding) { const double sqrt2 = 1.4142135623730950488016887242097; if(dir & 1) { Unit unitDistance = (Unit)bloating; if(rounding != SQRT2) { //45 degree bloating double distance = (double)bloating; distance /= sqrt2; // multiply by 1/sqrt2 unitDistance = roundWithOptions<Unit>(distance, rounding); } int xMultiplier = 1; int yMultiplier = 1; if(dir == 3 || dir == 5) xMultiplier = -1; if(dir == 5 || dir == 7) yMultiplier = -1; return point_data<Unit>(point.x()+xMultiplier*unitDistance, point.y()+yMultiplier*unitDistance); } else { if(dir == 0) return point_data<Unit>(point.x()+bloating, point.y()); if(dir == 2) return point_data<Unit>(point.x(), point.y()+bloating); if(dir == 4) return point_data<Unit>(point.x()-bloating, point.y()); if(dir == 6) return point_data<Unit>(point.x(), point.y()-bloating); return point_data<Unit>(); } } template <typename Unit> inline unsigned int getEdge45Direction(const point_data<Unit>& pt1, const point_data<Unit>& pt2) { if(pt1.x() == pt2.x()) { if(pt1.y() < pt2.y()) return 2; return 6; } if(pt1.y() == pt2.y()) { if(pt1.x() < pt2.x()) return 0; return 4; } if(pt2.y() > pt1.y()) { if(pt2.x() > pt1.x()) return 1; return 3; } if(pt2.x() > pt1.x()) return 7; return 5; } inline unsigned int getEdge45NormalDirection(unsigned int dir, int multiplier) { if(multiplier < 0) return (dir + 2) % 8; return (dir + 4 + 2) % 8; } template <typename Unit> inline point_data<Unit> getIntersectionPoint(const point_data<Unit>& pt1, unsigned int slope1, const point_data<Unit>& pt2, unsigned int slope2) { //the intention here is to use all integer arithmetic without causing overflow //turncation error or divide by zero error //I don't use floating point arithmetic because its precision may not be high enough //at the extremes of the integer range typedef typename coordinate_traits<Unit>::area_type LongUnit; const Unit rises[8] = {0, 1, 1, 1, 0, -1, -1, -1}; const Unit runs[8] = {1, 1, 0, -1, -1, -1, 0, 1}; LongUnit rise1 = rises[slope1]; LongUnit rise2 = rises[slope2]; LongUnit run1 = runs[slope1]; LongUnit run2 = runs[slope2]; LongUnit x1 = (LongUnit)pt1.x(); LongUnit x2 = (LongUnit)pt2.x(); LongUnit y1 = (LongUnit)pt1.y(); LongUnit y2 = (LongUnit)pt2.y(); Unit x = 0; Unit y = 0; if(run1 == 0) { x = pt1.x(); y = (Unit)(((x1 - x2) * rise2) / run2) + pt2.y(); } else if(run2 == 0) { x = pt2.x(); y = (Unit)(((x2 - x1) * rise1) / run1) + pt1.y(); } else { // y - y1 = (rise1/run1)(x - x1) // y - y2 = (rise2/run2)(x - x2) // y = (rise1/run1)(x - x1) + y1 = (rise2/run2)(x - x2) + y2 // (rise1/run1 - rise2/run2)x = y2 - y1 + rise1/run1 x1 - rise2/run2 x2 // x = (y2 - y1 + rise1/run1 x1 - rise2/run2 x2)/(rise1/run1 - rise2/run2) // x = (y2 - y1 + rise1/run1 x1 - rise2/run2 x2)(rise1 run2 - rise2 run1)/(run1 run2) x = (Unit)((y2 - y1 + ((rise1 * x1) / run1) - ((rise2 * x2) / run2)) * (run1 * run2) / (rise1 * run2 - rise2 * run1)); if(rise1 == 0) { y = pt1.y(); } else if(rise2 == 0) { y = pt2.y(); } else { // y - y1 = (rise1/run1)(x - x1) // (run1/rise1)(y - y1) = x - x1 // x = (run1/rise1)(y - y1) + x1 = (run2/rise2)(y - y2) + x2 y = (Unit)((x2 - x1 + ((run1 * y1) / rise1) - ((run2 * y2) / rise2)) * (rise1 * rise2) / (run1 * rise2 - run2 * rise1)); } } return point_data<Unit>(x, y); } template <typename Unit> inline void handleResizingEdge45_SQRT1OVER2(polygon_45_set_data<Unit>& sizingSet, point_data<Unit> first, point_data<Unit> second, Unit resizing, CornerOption corner) { if(first.x() == second.x()) { sizingSet.insert(rectangle_data<Unit>(first.x() - resizing, first.y(), first.x() + resizing, second.y())); return; } if(first.y() == second.y()) { sizingSet.insert(rectangle_data<Unit>(first.x(), first.y() - resizing, second.x(), first.y() + resizing)); return; } std::vector<point_data<Unit> > pts; Unit bloating = resizing < 0 ? -resizing : resizing; if(corner == UNFILLED) { //we have to round up bloating = bloating / 2 + bloating % 2 ; //round up if(second.x() < first.x()) std::swap(first, second); if(first.y() < second.y()) { //upward sloping pts.push_back(point_data<Unit>(first.x() + bloating, first.y() - bloating)); pts.push_back(point_data<Unit>(first.x() - bloating, first.y() + bloating)); pts.push_back(point_data<Unit>(second.x() - bloating, second.y() + bloating)); pts.push_back(point_data<Unit>(second.x() + bloating, second.y() - bloating)); sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), CLOCKWISE, false); } else { //downward sloping pts.push_back(point_data<Unit>(first.x() + bloating, first.y() + bloating)); pts.push_back(point_data<Unit>(first.x() - bloating, first.y() - bloating)); pts.push_back(point_data<Unit>(second.x() - bloating, second.y() - bloating)); pts.push_back(point_data<Unit>(second.x() + bloating, second.y() + bloating)); sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), COUNTERCLOCKWISE, false); } return; } if(second.x() < first.x()) std::swap(first, second); if(first.y() < second.y()) { //upward sloping pts.push_back(point_data<Unit>(first.x(), first.y() - bloating)); pts.push_back(point_data<Unit>(first.x() - bloating, first.y())); pts.push_back(point_data<Unit>(second.x(), second.y() + bloating)); pts.push_back(point_data<Unit>(second.x() + bloating, second.y())); sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), CLOCKWISE, false); } else { //downward sloping pts.push_back(point_data<Unit>(first.x() - bloating, first.y())); pts.push_back(point_data<Unit>(first.x(), first.y() + bloating)); pts.push_back(point_data<Unit>(second.x() + bloating, second.y())); pts.push_back(point_data<Unit>(second.x(), second.y() - bloating)); sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), CLOCKWISE, false); } } template <typename Unit> inline void handleResizingEdge45(polygon_45_set_data<Unit>& sizingSet, point_data<Unit> first, point_data<Unit> second, Unit resizing, RoundingOption rounding) { if(first.x() == second.x()) { sizingSet.insert(rectangle_data<int>(first.x() - resizing, first.y(), first.x() + resizing, second.y())); return; } if(first.y() == second.y()) { sizingSet.insert(rectangle_data<int>(first.x(), first.y() - resizing, second.x(), first.y() + resizing)); return; } //edge is 45 std::vector<point_data<Unit> > pts; Unit bloating = resizing < 0 ? -resizing : resizing; if(second.x() < first.x()) std::swap(first, second); if(first.y() < second.y()) { pts.push_back(bloatVertexInDirWithOptions(first, 3, bloating, rounding)); pts.push_back(bloatVertexInDirWithOptions(first, 7, bloating, rounding)); pts.push_back(bloatVertexInDirWithOptions(second, 7, bloating, rounding)); pts.push_back(bloatVertexInDirWithOptions(second, 3, bloating, rounding)); sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), HIGH, false); } else { pts.push_back(bloatVertexInDirWithOptions(first, 1, bloating, rounding)); pts.push_back(bloatVertexInDirWithOptions(first, 5, bloating, rounding)); pts.push_back(bloatVertexInDirWithOptions(second, 5, bloating, rounding)); pts.push_back(bloatVertexInDirWithOptions(second, 1, bloating, rounding)); sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), HIGH, false); } } template <typename Unit> inline point_data<Unit> bloatVertexInDirWithSQRT1OVER2(int edge1, int normal1, const point_data<Unit>& second, Unit bloating, bool first) { orientation_2d orient = first ? HORIZONTAL : VERTICAL; orientation_2d orientp = orient.get_perpendicular(); int multiplier = first ? 1 : -1; point_data<Unit> pt1(second); if(edge1 == 1) { if(normal1 == 3) { move(pt1, orient, -multiplier * bloating); } else { move(pt1, orientp, -multiplier * bloating); } } else if(edge1 == 3) { if(normal1 == 1) { move(pt1, orient, multiplier * bloating); } else { move(pt1, orientp, -multiplier * bloating); } } else if(edge1 == 5) { if(normal1 == 3) { move(pt1, orientp, multiplier * bloating); } else { move(pt1, orient, multiplier * bloating); } } else { if(normal1 == 5) { move(pt1, orient, -multiplier * bloating); } else { move(pt1, orientp, multiplier * bloating); } } return pt1; } template <typename Unit> inline void handleResizingVertex45(polygon_45_set_data<Unit>& sizingSet, const point_data<Unit>& first, const point_data<Unit>& second, const point_data<Unit>& third, Unit resizing, RoundingOption rounding, CornerOption corner, int multiplier) { unsigned int edge1 = getEdge45Direction(first, second); unsigned int edge2 = getEdge45Direction(second, third); unsigned int diffAngle; if(multiplier < 0) diffAngle = (edge2 + 8 - edge1) % 8; else diffAngle = (edge1 + 8 - edge2) % 8; if(diffAngle < 4) { if(resizing > 0) return; //accute interior corner else multiplier *= -1; //make it appear to be an accute exterior angle } Unit bloating = local_abs(resizing); if(rounding == SQRT1OVER2) { if(edge1 % 2 && edge2 % 2) return; if(corner == ORTHOGONAL && edge1 % 2 == 0 && edge2 % 2 == 0) { rectangle_data<Unit> insertion_rect; set_points(insertion_rect, second, second); bloat(insertion_rect, bloating); sizingSet.insert(insertion_rect); } else if(corner != ORTHOGONAL) { point_data<Unit> pt1(0, 0); point_data<Unit> pt2(0, 0); unsigned int normal1 = getEdge45NormalDirection(edge1, multiplier); unsigned int normal2 = getEdge45NormalDirection(edge2, multiplier); if(edge1 % 2) { pt1 = bloatVertexInDirWithSQRT1OVER2(edge1, normal1, second, bloating, true); } else { pt1 = bloatVertexInDirWithOptions(second, normal1, bloating, UNDERSIZE); } if(edge2 % 2) { pt2 = bloatVertexInDirWithSQRT1OVER2(edge2, normal2, second, bloating, false); } else { pt2 = bloatVertexInDirWithOptions(second, normal2, bloating, UNDERSIZE); } std::vector<point_data<Unit> > pts; pts.push_back(pt1); pts.push_back(second); pts.push_back(pt2); pts.push_back(getIntersectionPoint(pt1, edge1, pt2, edge2)); polygon_45_data<Unit> poly(pts.begin(), pts.end()); sizingSet.insert(poly); } else { //ORTHOGONAL of a 45 degree corner int normal = 0; if(edge1 % 2) { normal = getEdge45NormalDirection(edge2, multiplier); } else { normal = getEdge45NormalDirection(edge1, multiplier); } rectangle_data<Unit> insertion_rect; point_data<Unit> edgePoint = bloatVertexInDirWithOptions(second, normal, bloating, UNDERSIZE); set_points(insertion_rect, second, edgePoint); if(normal == 0 || normal == 4) bloat(insertion_rect, VERTICAL, bloating); else bloat(insertion_rect, HORIZONTAL, bloating); sizingSet.insert(insertion_rect); } return; } unsigned int normal1 = getEdge45NormalDirection(edge1, multiplier); unsigned int normal2 = getEdge45NormalDirection(edge2, multiplier); point_data<Unit> edgePoint1 = bloatVertexInDirWithOptions(second, normal1, bloating, rounding); point_data<Unit> edgePoint2 = bloatVertexInDirWithOptions(second, normal2, bloating, rounding); //if the change in angle is 135 degrees it is an accute exterior corner if((edge1+ multiplier * 3) % 8 == edge2) { if(corner == ORTHOGONAL) { rectangle_data<Unit> insertion_rect; set_points(insertion_rect, edgePoint1, edgePoint2); sizingSet.insert(insertion_rect); return; } } std::vector<point_data<Unit> > pts; pts.push_back(edgePoint1); pts.push_back(second); pts.push_back(edgePoint2); pts.push_back(getIntersectionPoint(edgePoint1, edge1, edgePoint2, edge2)); polygon_45_data<Unit> poly(pts.begin(), pts.end()); sizingSet.insert(poly); } template <typename Unit> template <typename geometry_type> inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, RoundingOption rounding, CornerOption corner, bool hole, polygon_45_concept ) { direction_1d wdir = winding(poly); int multiplier = wdir == LOW ? -1 : 1; if(hole) resizing *= -1; typedef typename polygon_45_data<Unit>::iterator_type piterator; piterator first, second, third, end, real_end; real_end = end_points(poly); third = begin_points(poly); first = third; if(first == real_end) return *this; ++third; if(third == real_end) return *this; second = end = third; ++third; if(third == real_end) return *this; polygon_45_set_data<Unit> sizingSet; //insert minkofski shapes on edges and corners do { if(rounding != SQRT1OVER2) { handleResizingEdge45(sizingSet, *first, *second, resizing, rounding); } else { handleResizingEdge45_SQRT1OVER2(sizingSet, *first, *second, resizing, corner); } if(corner != UNFILLED) handleResizingVertex45(sizingSet, *first, *second, *third, resizing, rounding, corner, multiplier); first = second; second = third; ++third; if(third == real_end) { third = begin_points(poly); if(*second == *third) { ++third; //skip first point if it is duplicate of last point } } } while(second != end); //sizingSet.snap(); polygon_45_set_data<Unit> tmp; //insert original shape tmp.insert_dispatch(poly, false, polygon_45_concept()); if(resizing < 0) tmp -= sizingSet; else tmp += sizingSet; tmp.clean(); insert(tmp, hole); dirty_ = true; unsorted_ = true; return (*this); } // accumulate the bloated polygon with holes template <typename Unit> template <typename geometry_type> inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, RoundingOption rounding, CornerOption corner, bool hole, polygon_45_with_holes_concept ) { insert_with_resize_dispatch(poly, resizing, rounding, corner, hole, polygon_45_concept()); for(typename polygon_with_holes_traits<geometry_type>::iterator_holes_type itr = begin_holes(poly); itr != end_holes(poly); ++itr) { insert_with_resize_dispatch(*itr, resizing, rounding, corner, !hole, polygon_45_concept()); } return *this; } // transform set template <typename Unit> template <typename transformation_type> inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::transform(const transformation_type& tr){ clean(); std::vector<polygon_45_with_holes_data<Unit> > polys; get(polys); for(typename std::vector<polygon_45_with_holes_data<Unit> >::iterator itr = polys.begin(); itr != polys.end(); ++itr) { ::boost::polygon::transform(*itr, tr); } clear(); insert(polys.begin(), polys.end()); dirty_ = true; unsorted_ = true; return *this; } template <typename Unit> inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::scale_up(typename coordinate_traits<Unit>::unsigned_area_type factor) { scale_up_vertex_45_compact_range(data_.begin(), data_.end(), factor); return *this; } template <typename Unit> inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::scale_down(typename coordinate_traits<Unit>::unsigned_area_type factor) { clean(); std::vector<polygon_45_with_holes_data<Unit> > polys; get_polygons_with_holes(polys); for(typename std::vector<polygon_45_with_holes_data<Unit> >::iterator itr = polys.begin(); itr != polys.end(); ++itr) { ::boost::polygon::scale_down(*itr, factor); } clear(); insert(polys.begin(), polys.end()); dirty_ = true; unsorted_ = true; return *this; } template <typename Unit> inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::scale(double factor) { clean(); std::vector<polygon_45_with_holes_data<Unit> > polys; get_polygons_with_holes(polys); for(typename std::vector<polygon_45_with_holes_data<Unit> >::iterator itr = polys.begin(); itr != polys.end(); ++itr) { ::boost::polygon::scale(*itr, factor); } clear(); insert(polys.begin(), polys.end()); dirty_ = true; unsorted_ = true; return *this; } template <typename Unit> inline bool polygon_45_set_data<Unit>::clean() const { if(unsorted_) sort(); if(dirty_) { applyAdaptiveUnary_<0>(); dirty_ = false; } return true; } template <typename Unit> template <int op> inline void polygon_45_set_data<Unit>::applyAdaptiveBoolean_(const polygon_45_set_data<Unit>& rvalue) const { polygon_45_set_data<Unit> tmp; applyAdaptiveBoolean_<op>(tmp, rvalue); data_.swap(tmp.data_); //swapping vectors should be constant time operation error_data_.swap(tmp.error_data_); is_manhattan_ = tmp.is_manhattan_; unsorted_ = false; dirty_ = false; } template <typename Unit2, int op> bool applyBoolean45OpOnVectors(std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact>& result_data, std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact>& lvalue_data, std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact>& rvalue_data ) { bool result_is_manhattan_ = true; typename boolean_op_45<Unit2>::template Scan45<typename boolean_op_45<Unit2>::Count2, typename boolean_op_45<Unit2>::template boolean_op_45_output_functor<op> > scan45; std::vector<typename boolean_op_45<Unit2>::Vertex45> eventOut; typedef std::pair<typename boolean_op_45<Unit2>::Point, typename boolean_op_45<Unit2>::template Scan45CountT<typename boolean_op_45<Unit2>::Count2> > Scan45Vertex; std::vector<Scan45Vertex> eventIn; typedef std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact> value_type; typename value_type::const_iterator iter1 = lvalue_data.begin(); typename value_type::const_iterator iter2 = rvalue_data.begin(); typename value_type::const_iterator end1 = lvalue_data.end(); typename value_type::const_iterator end2 = rvalue_data.end(); const Unit2 UnitMax = (std::numeric_limits<Unit2>::max)(); Unit2 x = UnitMax; while(iter1 != end1 || iter2 != end2) { Unit2 currentX = UnitMax; if(iter1 != end1) currentX = iter1->pt.x(); if(iter2 != end2) currentX = (std::min)(currentX, iter2->pt.x()); if(currentX != x) { //std::cout << "SCAN " << currentX << "\n"; //scan event scan45.scan(eventOut, eventIn.begin(), eventIn.end()); polygon_sort(eventOut.begin(), eventOut.end()); std::size_t ptCount = 0; for(std::size_t i = 0; i < eventOut.size(); ++i) { if(!result_data.empty() && result_data.back().pt == eventOut[i].pt) { result_data.back().count += eventOut[i]; ++ptCount; } else { if(!result_data.empty()) { if(result_data.back().count.is_45()) { result_is_manhattan_ = false; } if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { result_data.pop_back(); } } result_data.push_back(eventOut[i]); ptCount = 1; } } if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { result_data.pop_back(); } eventOut.clear(); eventIn.clear(); x = currentX; } //std::cout << "get next\n"; if(iter2 != end2 && (iter1 == end1 || iter2->pt.x() < iter1->pt.x() || (iter2->pt.x() == iter1->pt.x() && iter2->pt.y() < iter1->pt.y()) )) { //std::cout << "case1 next\n"; eventIn.push_back(Scan45Vertex (iter2->pt, typename polygon_45_formation<Unit2>:: Scan45Count(typename polygon_45_formation<Unit2>::Count2(0, iter2->count[0]), typename polygon_45_formation<Unit2>::Count2(0, iter2->count[1]), typename polygon_45_formation<Unit2>::Count2(0, iter2->count[2]), typename polygon_45_formation<Unit2>::Count2(0, iter2->count[3])))); ++iter2; } else if(iter1 != end1 && (iter2 == end2 || iter1->pt.x() < iter2->pt.x() || (iter1->pt.x() == iter2->pt.x() && iter1->pt.y() < iter2->pt.y()) )) { //std::cout << "case2 next\n"; eventIn.push_back(Scan45Vertex (iter1->pt, typename polygon_45_formation<Unit2>:: Scan45Count( typename polygon_45_formation<Unit2>::Count2(iter1->count[0], 0), typename polygon_45_formation<Unit2>::Count2(iter1->count[1], 0), typename polygon_45_formation<Unit2>::Count2(iter1->count[2], 0), typename polygon_45_formation<Unit2>::Count2(iter1->count[3], 0)))); ++iter1; } else { //std::cout << "case3 next\n"; eventIn.push_back(Scan45Vertex (iter2->pt, typename polygon_45_formation<Unit2>:: Scan45Count(typename polygon_45_formation<Unit2>::Count2(iter1->count[0], iter2->count[0]), typename polygon_45_formation<Unit2>::Count2(iter1->count[1], iter2->count[1]), typename polygon_45_formation<Unit2>::Count2(iter1->count[2], iter2->count[2]), typename polygon_45_formation<Unit2>::Count2(iter1->count[3], iter2->count[3])))); ++iter1; ++iter2; } } scan45.scan(eventOut, eventIn.begin(), eventIn.end()); polygon_sort(eventOut.begin(), eventOut.end()); std::size_t ptCount = 0; for(std::size_t i = 0; i < eventOut.size(); ++i) { if(!result_data.empty() && result_data.back().pt == eventOut[i].pt) { result_data.back().count += eventOut[i]; ++ptCount; } else { if(!result_data.empty()) { if(result_data.back().count.is_45()) { result_is_manhattan_ = false; } if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { result_data.pop_back(); } } result_data.push_back(eventOut[i]); ptCount = 1; } } if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { result_data.pop_back(); } if(!result_data.empty() && result_data.back().count.is_45()) { result_is_manhattan_ = false; } return result_is_manhattan_; } template <typename Unit2, int op> bool applyUnary45OpOnVectors(std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact>& result_data, std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact>& lvalue_data ) { bool result_is_manhattan_ = true; typename boolean_op_45<Unit2>::template Scan45<typename boolean_op_45<Unit2>::Count1, typename boolean_op_45<Unit2>::template unary_op_45_output_functor<op> > scan45; std::vector<typename boolean_op_45<Unit2>::Vertex45> eventOut; typedef typename boolean_op_45<Unit2>::template Scan45CountT<typename boolean_op_45<Unit2>::Count1> Scan45Count; typedef std::pair<typename boolean_op_45<Unit2>::Point, Scan45Count> Scan45Vertex; std::vector<Scan45Vertex> eventIn; typedef std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact> value_type; typename value_type::const_iterator iter1 = lvalue_data.begin(); typename value_type::const_iterator end1 = lvalue_data.end(); const Unit2 UnitMax = (std::numeric_limits<Unit2>::max)(); Unit2 x = UnitMax; while(iter1 != end1) { Unit2 currentX = iter1->pt.x(); if(currentX != x) { //std::cout << "SCAN " << currentX << "\n"; //scan event scan45.scan(eventOut, eventIn.begin(), eventIn.end()); polygon_sort(eventOut.begin(), eventOut.end()); std::size_t ptCount = 0; for(std::size_t i = 0; i < eventOut.size(); ++i) { if(!result_data.empty() && result_data.back().pt == eventOut[i].pt) { result_data.back().count += eventOut[i]; ++ptCount; } else { if(!result_data.empty()) { if(result_data.back().count.is_45()) { result_is_manhattan_ = false; } if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { result_data.pop_back(); } } result_data.push_back(eventOut[i]); ptCount = 1; } } if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { result_data.pop_back(); } eventOut.clear(); eventIn.clear(); x = currentX; } //std::cout << "get next\n"; eventIn.push_back(Scan45Vertex (iter1->pt, Scan45Count( typename boolean_op_45<Unit2>::Count1(iter1->count[0]), typename boolean_op_45<Unit2>::Count1(iter1->count[1]), typename boolean_op_45<Unit2>::Count1(iter1->count[2]), typename boolean_op_45<Unit2>::Count1(iter1->count[3])))); ++iter1; } scan45.scan(eventOut, eventIn.begin(), eventIn.end()); polygon_sort(eventOut.begin(), eventOut.end()); std::size_t ptCount = 0; for(std::size_t i = 0; i < eventOut.size(); ++i) { if(!result_data.empty() && result_data.back().pt == eventOut[i].pt) { result_data.back().count += eventOut[i]; ++ptCount; } else { if(!result_data.empty()) { if(result_data.back().count.is_45()) { result_is_manhattan_ = false; } if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { result_data.pop_back(); } } result_data.push_back(eventOut[i]); ptCount = 1; } } if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { result_data.pop_back(); } if(!result_data.empty() && result_data.back().count.is_45()) { result_is_manhattan_ = false; } return result_is_manhattan_; } template <typename cT, typename iT> void get_error_rects_shell(cT& posE, cT& negE, iT beginr, iT endr) { typedef typename std::iterator_traits<iT>::value_type Point; typedef typename point_traits<Point>::coordinate_type Unit; typedef typename coordinate_traits<Unit>::area_type area_type; Point pt1, pt2, pt3; bool i1 = true; bool i2 = true; bool not_done = beginr != endr; bool next_to_last = false; bool last = false; Point first, second; while(not_done) { if(last) { last = false; not_done = false; pt3 = second; } else if(next_to_last) { next_to_last = false; last = true; pt3 = first; } else if(i1) { const Point& pt = *beginr; first = pt1 = pt; i1 = false; i2 = true; ++beginr; if(beginr == endr) return; //too few points continue; } else if (i2) { const Point& pt = *beginr; second = pt2 = pt; i2 = false; ++beginr; if(beginr == endr) return; //too few points continue; } else { const Point& pt = *beginr; pt3 = pt; ++beginr; if(beginr == endr) { next_to_last = true; //skip last point equal to first continue; } } if(local_abs(x(pt2)) % 2) { //y % 2 should also be odd //is corner concave or convex? Point pts[] = {pt1, pt2, pt3}; area_type ar = point_sequence_area<Point*, area_type>(pts, pts+3); direction_1d dir = ar < 0 ? COUNTERCLOCKWISE : CLOCKWISE; //std::cout << pt1 << " " << pt2 << " " << pt3 << " " << ar << std::endl; if(dir == CLOCKWISE) { posE.push_back(rectangle_data<typename Point::coordinate_type> (x(pt2) - 1, y(pt2) - 1, x(pt2) + 1, y(pt2) + 1)); } else { negE.push_back(rectangle_data<typename Point::coordinate_type> (x(pt2) - 1, y(pt2) - 1, x(pt2) + 1, y(pt2) + 1)); } } pt1 = pt2; pt2 = pt3; } } template <typename cT, typename pT> void get_error_rects(cT& posE, cT& negE, const pT& p) { get_error_rects_shell(posE, negE, p.begin(), p.end()); for(typename pT::iterator_holes_type iHb = p.begin_holes(); iHb != p.end_holes(); ++iHb) { get_error_rects_shell(posE, negE, iHb->begin(), iHb->end()); } } template <typename Unit> template <int op> inline void polygon_45_set_data<Unit>::applyAdaptiveBoolean_(polygon_45_set_data<Unit>& result, const polygon_45_set_data<Unit>& rvalue) const { result.clear(); result.error_data_ = error_data_; result.error_data_.insert(result.error_data_.end(), rvalue.error_data_.begin(), rvalue.error_data_.end()); if(is_manhattan() && rvalue.is_manhattan()) { //convert each into polygon_90_set data and call boolean operations polygon_90_set_data<Unit> l90sd(VERTICAL), r90sd(VERTICAL), output(VERTICAL); for(typename value_type::const_iterator itr = data_.begin(); itr != data_.end(); ++itr) { if((*itr).count[3] == 0) continue; //skip all non vertical edges l90sd.insert(std::make_pair((*itr).pt.x(), std::make_pair<Unit, int>((*itr).pt.y(), (*itr).count[3])), false, VERTICAL); } for(typename value_type::const_iterator itr = rvalue.data_.begin(); itr != rvalue.data_.end(); ++itr) { if((*itr).count[3] == 0) continue; //skip all non vertical edges r90sd.insert(std::make_pair((*itr).pt.x(), std::make_pair<Unit, int>((*itr).pt.y(), (*itr).count[3])), false, VERTICAL); } l90sd.sort(); r90sd.sort(); #ifdef BOOST_POLYGON_MSVC #pragma warning (push) #pragma warning (disable: 4127) #endif if(op == 0) { output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), r90sd.begin(), r90sd.end(), boolean_op::BinaryCount<boolean_op::BinaryOr>()); } else if (op == 1) { output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), r90sd.begin(), r90sd.end(), boolean_op::BinaryCount<boolean_op::BinaryAnd>()); } else if (op == 2) { output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), r90sd.begin(), r90sd.end(), boolean_op::BinaryCount<boolean_op::BinaryNot>()); } else if (op == 3) { output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), r90sd.begin(), r90sd.end(), boolean_op::BinaryCount<boolean_op::BinaryXor>()); } #ifdef BOOST_POLYGON_MSVC #pragma warning (pop) #endif result.data_.clear(); result.insert(output); result.is_manhattan_ = true; result.dirty_ = false; result.unsorted_ = false; } else { sort(); rvalue.sort(); try { result.is_manhattan_ = applyBoolean45OpOnVectors<Unit, op>(result.data_, data_, rvalue.data_); } catch (std::string str) { std::string msg = "GTL 45 Boolean error, precision insufficient to represent edge intersection coordinate value."; if(str == msg) { result.clear(); typedef typename coordinate_traits<Unit>::manhattan_area_type Unit2; typedef typename polygon_45_formation<Unit2>::Vertex45Compact Vertex45Compact2; typedef std::vector<Vertex45Compact2> Data2; Data2 rvalue_data, lvalue_data, result_data; rvalue_data.reserve(rvalue.data_.size()); lvalue_data.reserve(data_.size()); for(std::size_t i = 0 ; i < data_.size(); ++i) { const Vertex45Compact& vi = data_[i]; Vertex45Compact2 ci; ci.pt = point_data<Unit2>(x(vi.pt), y(vi.pt)); ci.count = typename polygon_45_formation<Unit2>::Vertex45Count ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); lvalue_data.push_back(ci); } for(std::size_t i = 0 ; i < rvalue.data_.size(); ++i) { const Vertex45Compact& vi = rvalue.data_[i]; Vertex45Compact2 ci; ci.pt = (point_data<Unit2>(x(vi.pt), y(vi.pt))); ci.count = typename polygon_45_formation<Unit2>::Vertex45Count ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); rvalue_data.push_back(ci); } scale_up_vertex_45_compact_range(lvalue_data.begin(), lvalue_data.end(), 2); scale_up_vertex_45_compact_range(rvalue_data.begin(), rvalue_data.end(), 2); bool result_is_manhattan = applyBoolean45OpOnVectors<Unit2, op>(result_data, lvalue_data, rvalue_data ); if(!result_is_manhattan) { typename polygon_45_formation<Unit2>::Polygon45Formation pf(false); //std::cout << "FORMING POLYGONS\n"; std::vector<polygon_45_with_holes_data<Unit2> > container; pf.scan(container, result_data.begin(), result_data.end()); Data2 error_data_out; std::vector<rectangle_data<Unit2> > pos_error_rects; std::vector<rectangle_data<Unit2> > neg_error_rects; for(std::size_t i = 0; i < container.size(); ++i) { get_error_rects(pos_error_rects, neg_error_rects, container[i]); } for(std::size_t i = 0; i < pos_error_rects.size(); ++i) { insert_rectangle_into_vector_45(result_data, pos_error_rects[i], false); insert_rectangle_into_vector_45(error_data_out, pos_error_rects[i], false); } for(std::size_t i = 0; i < neg_error_rects.size(); ++i) { insert_rectangle_into_vector_45(result_data, neg_error_rects[i], true); insert_rectangle_into_vector_45(error_data_out, neg_error_rects[i], false); } scale_down_vertex_45_compact_range_blindly(error_data_out.begin(), error_data_out.end(), 2); for(std::size_t i = 0 ; i < error_data_out.size(); ++i) { const Vertex45Compact2& vi = error_data_out[i]; Vertex45Compact ci; ci.pt.x(static_cast<Unit>(x(vi.pt))); ci.pt.y(static_cast<Unit>(y(vi.pt))); ci.count = typename polygon_45_formation<Unit>::Vertex45Count ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); result.error_data_.push_back(ci); } Data2 new_result_data; polygon_sort(result_data.begin(), result_data.end()); applyUnary45OpOnVectors<Unit2, 0>(new_result_data, result_data); //OR operation result_data.swap(new_result_data); } scale_down_vertex_45_compact_range_blindly(result_data.begin(), result_data.end(), 2); //result.data_.reserve(result_data.size()); for(std::size_t i = 0 ; i < result_data.size(); ++i) { const Vertex45Compact2& vi = result_data[i]; Vertex45Compact ci; ci.pt.x(static_cast<Unit>(x(vi.pt))); ci.pt.y(static_cast<Unit>(y(vi.pt))); ci.count = typename polygon_45_formation<Unit>::Vertex45Count ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); result.data_.push_back(ci); } result.is_manhattan_ = result_is_manhattan; result.dirty_ = false; result.unsorted_ = false; } else { throw str; } } //std::cout << "DONE SCANNING\n"; } } template <typename Unit> template <int op> inline void polygon_45_set_data<Unit>::applyAdaptiveUnary_() const { polygon_45_set_data<Unit> result; result.error_data_ = error_data_; if(is_manhattan()) { //convert each into polygon_90_set data and call boolean operations polygon_90_set_data<Unit> l90sd(VERTICAL); for(typename value_type::const_iterator itr = data_.begin(); itr != data_.end(); ++itr) { if((*itr).count[3] == 0) continue; //skip all non vertical edges l90sd.insert(std::make_pair((*itr).pt.x(), std::make_pair<Unit, int>((*itr).pt.y(), (*itr).count[3])), false, VERTICAL); } l90sd.sort(); #ifdef BOOST_POLYGON_MSVC #pragma warning (push) #pragma warning (disable: 4127) #endif if(op == 0) { l90sd.clean(); } else if (op == 1) { l90sd.self_intersect(); } else if (op == 3) { l90sd.self_xor(); } #ifdef BOOST_POLYGON_MSVC #pragma warning (pop) #endif result.data_.clear(); result.insert(l90sd); result.is_manhattan_ = true; result.dirty_ = false; result.unsorted_ = false; } else { sort(); try { result.is_manhattan_ = applyUnary45OpOnVectors<Unit, op>(result.data_, data_); } catch (std::string str) { std::string msg = "GTL 45 Boolean error, precision insufficient to represent edge intersection coordinate value."; if(str == msg) { result.clear(); typedef typename coordinate_traits<Unit>::manhattan_area_type Unit2; typedef typename polygon_45_formation<Unit2>::Vertex45Compact Vertex45Compact2; typedef std::vector<Vertex45Compact2> Data2; Data2 lvalue_data, result_data; lvalue_data.reserve(data_.size()); for(std::size_t i = 0 ; i < data_.size(); ++i) { const Vertex45Compact& vi = data_[i]; Vertex45Compact2 ci; ci.pt.x(static_cast<Unit>(x(vi.pt))); ci.pt.y(static_cast<Unit>(y(vi.pt))); ci.count = typename polygon_45_formation<Unit2>::Vertex45Count ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); lvalue_data.push_back(ci); } scale_up_vertex_45_compact_range(lvalue_data.begin(), lvalue_data.end(), 2); bool result_is_manhattan = applyUnary45OpOnVectors<Unit2, op>(result_data, lvalue_data ); if(!result_is_manhattan) { typename polygon_45_formation<Unit2>::Polygon45Formation pf(false); //std::cout << "FORMING POLYGONS\n"; std::vector<polygon_45_with_holes_data<Unit2> > container; pf.scan(container, result_data.begin(), result_data.end()); Data2 error_data_out; std::vector<rectangle_data<Unit2> > pos_error_rects; std::vector<rectangle_data<Unit2> > neg_error_rects; for(std::size_t i = 0; i < container.size(); ++i) { get_error_rects(pos_error_rects, neg_error_rects, container[i]); } for(std::size_t i = 0; i < pos_error_rects.size(); ++i) { insert_rectangle_into_vector_45(result_data, pos_error_rects[i], false); insert_rectangle_into_vector_45(error_data_out, pos_error_rects[i], false); } for(std::size_t i = 0; i < neg_error_rects.size(); ++i) { insert_rectangle_into_vector_45(result_data, neg_error_rects[i], true); insert_rectangle_into_vector_45(error_data_out, neg_error_rects[i], false); } scale_down_vertex_45_compact_range_blindly(error_data_out.begin(), error_data_out.end(), 2); for(std::size_t i = 0 ; i < error_data_out.size(); ++i) { const Vertex45Compact2& vi = error_data_out[i]; Vertex45Compact ci; ci.pt.x(static_cast<Unit>(x(vi.pt))); ci.pt.y(static_cast<Unit>(y(vi.pt))); ci.count = typename polygon_45_formation<Unit>::Vertex45Count ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); result.error_data_.push_back(ci); } Data2 new_result_data; polygon_sort(result_data.begin(), result_data.end()); applyUnary45OpOnVectors<Unit2, 0>(new_result_data, result_data); //OR operation result_data.swap(new_result_data); } scale_down_vertex_45_compact_range_blindly(result_data.begin(), result_data.end(), 2); //result.data_.reserve(result_data.size()); for(std::size_t i = 0 ; i < result_data.size(); ++i) { const Vertex45Compact2& vi = result_data[i]; Vertex45Compact ci; ci.pt.x(static_cast<Unit>(x(vi.pt))); ci.pt.y(static_cast<Unit>(y(vi.pt))); ci.count = typename polygon_45_formation<Unit>::Vertex45Count ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); result.data_.push_back(ci); } result.is_manhattan_ = result_is_manhattan; result.dirty_ = false; result.unsorted_ = false; } else { throw str; } } //std::cout << "DONE SCANNING\n"; } data_.swap(result.data_); error_data_.swap(result.error_data_); dirty_ = result.dirty_; unsorted_ = result.unsorted_; is_manhattan_ = result.is_manhattan_; } template <typename coordinate_type, typename property_type> class property_merge_45 { private: typedef typename coordinate_traits<coordinate_type>::manhattan_area_type big_coord; typedef typename polygon_45_property_merge<big_coord, property_type>::MergeSetData tsd; tsd tsd_; public: inline property_merge_45() : tsd_() {} inline property_merge_45(const property_merge_45& that) : tsd_(that.tsd_) {} inline property_merge_45& operator=(const property_merge_45& that) { tsd_ = that.tsd_; return *this; } inline void insert(const polygon_45_set_data<coordinate_type>& ps, property_type property) { ps.clean(); polygon_45_property_merge<big_coord, property_type>::populateMergeSetData(tsd_, ps.begin(), ps.end(), property); } template <class GeoObjT> inline void insert(const GeoObjT& geoObj, property_type property) { polygon_45_set_data<coordinate_type> 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<std::set<property_type>, polygon_45_set_data<coordiante_type> > or // T = std::map<std::vector<property_type>, polygon_45_set_data<coordiante_type> > template <class result_type> inline void merge(result_type& result) { typedef typename result_type::key_type keytype; typedef std::map<keytype, polygon_45_set_data<big_coord> > bigtype; bigtype result_big; polygon_45_property_merge<big_coord, property_type>::performMerge(result_big, tsd_); std::vector<polygon_45_with_holes_data<big_coord> > polys; std::vector<rectangle_data<big_coord> > pos_error_rects; std::vector<rectangle_data<big_coord> > neg_error_rects; for(typename std::map<keytype, polygon_45_set_data<big_coord> >::iterator itr = result_big.begin(); itr != result_big.end(); ++itr) { polys.clear(); (*itr).second.get(polys); for(std::size_t i = 0; i < polys.size(); ++i) { get_error_rects(pos_error_rects, neg_error_rects, polys[i]); } (*itr).second += pos_error_rects; (*itr).second -= neg_error_rects; (*itr).second.scale_down(2); result[(*itr).first].insert((*itr).second); } } }; //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 <typename coordinate_type> class connectivity_extraction_45 { private: typedef typename coordinate_traits<coordinate_type>::manhattan_area_type big_coord; typedef typename polygon_45_touch<big_coord>::TouchSetData tsd; tsd tsd_; unsigned int nodeCount_; public: inline connectivity_extraction_45() : tsd_(), nodeCount_(0) {} inline connectivity_extraction_45(const connectivity_extraction_45& that) : tsd_(that.tsd_), nodeCount_(that.nodeCount_) {} inline connectivity_extraction_45& operator=(const connectivity_extraction_45& 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_45_set_data<coordinate_type>& ps) { ps.clean(); polygon_45_touch<big_coord>::populateTouchSetData(tsd_, ps.begin(), ps.end(), nodeCount_); return nodeCount_++; } template <class GeoObjT> inline unsigned int insert(const GeoObjT& geoObj) { polygon_45_set_data<coordinate_type> 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 <class GraphT> inline void extract(GraphT& graph) { polygon_45_touch<big_coord>::performTouch(graph, tsd_); } }; } } #endif polygon_90_data.hpp 0000644 00000005510 15125572616 0010260 0 ustar 00 /* 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_DATA_HPP #define BOOST_POLYGON_POLYGON_90_DATA_HPP namespace boost { namespace polygon{ struct polygon_90_concept; template <typename T> class polygon_90_data { public: typedef polygon_90_concept geometry_type; typedef T coordinate_type; typedef typename std::vector<coordinate_type>::const_iterator compact_iterator_type; typedef iterator_compact_to_points<compact_iterator_type, point_data<coordinate_type> > iterator_type; typedef typename coordinate_traits<T>::area_type area_type; inline polygon_90_data() : coords_() {} //do nothing default constructor // initialize a polygon from x,y values, it is assumed that the first is an x // and that the input is a well behaved polygon template<class iT> inline polygon_90_data& set(iT begin_point, iT end_point) { return set_compact(iterator_points_to_compact<iT, typename std::iterator_traits<iT>::value_type>(begin_point, end_point), iterator_points_to_compact<iT, typename std::iterator_traits<iT>::value_type>(end_point, end_point)); } template<class iT> inline polygon_90_data& set_compact(iT input_begin, iT input_end) { coords_.clear(); //just in case there was some old data there while(input_begin != input_end) { coords_.insert(coords_.end(), *input_begin); ++input_begin; } return *this; } // copy constructor (since we have dynamic memory) inline polygon_90_data(const polygon_90_data& that) : coords_(that.coords_) {} // assignment operator (since we have dynamic memory do a deep copy) inline polygon_90_data& operator=(const polygon_90_data& that) { coords_ = that.coords_; return *this; } template <typename T2> inline polygon_90_data& operator=(const T2& rvalue); // assignment operator (since we have dynamic memory do a deep copy) inline bool operator==(const polygon_90_data& that) const { return coords_ == that.coords_; } // get begin iterator, returns a pointer to a const Unit inline iterator_type begin() const { return iterator_type(coords_.begin(), coords_.end()); } // get end iterator, returns a pointer to a const Unit inline iterator_type end() const { return iterator_type(coords_.end(), coords_.end()); } // get begin iterator, returns a pointer to a const Unit inline compact_iterator_type begin_compact() const { return coords_.begin(); } // get end iterator, returns a pointer to a const Unit inline compact_iterator_type end_compact() const { return coords_.end(); } inline std::size_t size() const { return coords_.size(); } private: std::vector<coordinate_type> coords_; }; } } #endif gtl.hpp 0000644 00000001270 15125572616 0006055 0 ustar 00 /* 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_GTL_HPP #define BOOST_POLYGON_GTL_HPP #ifdef __ICC #pragma warning (push) #pragma warning (disable:1125) #endif #ifdef WIN32 #pragma warning (push) #pragma warning( disable: 4996 ) #pragma warning( disable: 4800 ) #endif #define BOOST_POLYGON_NO_DEPS #include "polygon.hpp" namespace gtl = boost::polygon; using namespace boost::polygon::operators; #ifdef WIN32 #pragma warning (pop) #endif #ifdef __ICC #pragma warning (pop) #endif #endif rectangle_data.hpp 0000644 00000004110 15125572616 0010220 0 ustar 00 /* 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_RECTANGLE_DATA_HPP #define BOOST_POLYGON_RECTANGLE_DATA_HPP #include "isotropy.hpp" //interval #include "interval_data.hpp" namespace boost { namespace polygon{ template <typename T> class rectangle_data { public: typedef T coordinate_type; typedef interval_data<T> interval_type; inline rectangle_data():ranges_() {} inline rectangle_data(T xl, T yl, T xh, T yh):ranges_() { if(xl > xh) std::swap(xl, xh); if(yl > yh) std::swap(yl, yh); ranges_[HORIZONTAL] = interval_data<T>(xl, xh); ranges_[VERTICAL] = interval_data<T>(yl, yh); } template <typename interval_type_1, typename interval_type_2> inline rectangle_data(const interval_type_1& hrange, const interval_type_2& vrange):ranges_() { set(HORIZONTAL, hrange); set(VERTICAL, vrange); } inline rectangle_data(const rectangle_data& that):ranges_() { (*this) = that; } inline rectangle_data& operator=(const rectangle_data& that) { ranges_[0] = that.ranges_[0]; ranges_[1] = that.ranges_[1]; return *this; } template <typename T2> inline rectangle_data& operator=(const T2& rvalue); template <typename T2> inline bool operator==(const T2& rvalue) const; template <typename T2> inline bool operator!=(const T2& rvalue) const { return !((*this) == rvalue); } inline interval_data<coordinate_type> get(orientation_2d orient) const { return ranges_[orient.to_int()]; } inline coordinate_type get(direction_2d dir) const { return ranges_[orientation_2d(dir).to_int()].get(direction_1d(dir)); } inline void set(direction_2d dir, coordinate_type value) { return ranges_[orientation_2d(dir).to_int()].set(direction_1d(dir), value); } template <typename interval_type_1> inline void set(orientation_2d orient, const interval_type_1& interval); private: interval_data<coordinate_type> ranges_[2]; }; } } #endif interval_data.hpp 0000644 00000005215 15125572616 0010107 0 ustar 00 // Boost.Polygon library interval_data.hpp header file // Copyright (c) Intel Corporation 2008. // Copyright (c) 2008-2012 Simonson Lucanus. // Copyright (c) 2012-2012 Andrii Sydorchuk. // See http://www.boost.org for updates, documentation, and revision history. // Use, modification and distribution is 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_INTERVAL_DATA_HPP #define BOOST_POLYGON_INTERVAL_DATA_HPP #include "isotropy.hpp" #include "interval_concept.hpp" namespace boost { namespace polygon { template <typename T> class interval_data { public: typedef T coordinate_type; interval_data() #ifndef BOOST_POLYGON_MSVC : coords_() #endif {} interval_data(coordinate_type low, coordinate_type high) { coords_[LOW] = low; coords_[HIGH] = high; } interval_data(const interval_data& that) { coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; } interval_data& operator=(const interval_data& that) { coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; return *this; } template <typename IntervalType> interval_data& operator=(const IntervalType& that) { assign(*this, that); return *this; } coordinate_type get(direction_1d dir) const { return coords_[dir.to_int()]; } void set(direction_1d dir, coordinate_type value) { coords_[dir.to_int()] = value; } coordinate_type low() const { return coords_[0]; } interval_data& low(coordinate_type value) { coords_[LOW] = value; return *this; } coordinate_type high() const { return coords_[1]; } interval_data& high(coordinate_type value) { coords_[HIGH] = value; return *this; } bool operator==(const interval_data& that) const { return low() == that.low() && high() == that.high(); } bool operator!=(const interval_data& that) const { return low() != that.low() || high() != that.high(); } bool operator<(const interval_data& that) const { if (coords_[0] != that.coords_[0]) { return coords_[0] < that.coords_[0]; } return coords_[1] < that.coords_[1]; } bool operator<=(const interval_data& that) const { return !(that < *this); } bool operator>(const interval_data& that) const { return that < *this; } bool operator>=(const interval_data& that) const { return !((*this) < that); } private: coordinate_type coords_[2]; }; template <typename CType> struct geometry_concept< interval_data<CType> > { typedef interval_concept type; }; } // polygon } // boost #endif // BOOST_POLYGON_INTERVAL_DATA_HPP polygon_90_set_concept.hpp 0000644 00000064453 15125572616 0011670 0 ustar 00 /* 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_CONCEPT_HPP #define BOOST_POLYGON_POLYGON_90_SET_CONCEPT_HPP #include "polygon_90_set_data.hpp" #include "polygon_90_set_traits.hpp" namespace boost { namespace polygon{ template <typename polygon_set_type> typename enable_if< typename is_polygon_90_set_type<polygon_set_type>::type, typename polygon_90_set_traits<polygon_set_type>::iterator_type>::type begin_90_set_data(const polygon_set_type& polygon_set) { return polygon_90_set_traits<polygon_set_type>::begin(polygon_set); } template <typename polygon_set_type> typename enable_if< typename is_polygon_90_set_type<polygon_set_type>::type, typename polygon_90_set_traits<polygon_set_type>::iterator_type>::type end_90_set_data(const polygon_set_type& polygon_set) { return polygon_90_set_traits<polygon_set_type>::end(polygon_set); } template <typename polygon_set_type> typename enable_if< typename is_polygon_90_set_type<polygon_set_type>::type, orientation_2d>::type scanline_orientation(const polygon_set_type& polygon_set) { return polygon_90_set_traits<polygon_set_type>::orient(polygon_set); } template <typename polygon_set_type> typename enable_if< typename is_polygon_90_set_type<polygon_set_type>::type, bool>::type clean(const polygon_set_type& polygon_set) { return polygon_90_set_traits<polygon_set_type>::clean(polygon_set); } //assign template <typename polygon_set_type_1, typename polygon_set_type_2> typename enable_if < typename gtl_and< typename is_mutable_polygon_90_set_type<polygon_set_type_1>::type, typename is_polygon_90_set_type<polygon_set_type_2>::type>::type, polygon_set_type_1>::type & assign(polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { polygon_90_set_mutable_traits<polygon_set_type_1>::set(lvalue, begin_90_set_data(rvalue), end_90_set_data(rvalue), scanline_orientation(rvalue)); return lvalue; } template <typename T1, typename T2> struct are_not_both_rectangle_concept { typedef gtl_yes type; }; template <> struct are_not_both_rectangle_concept<rectangle_concept, rectangle_concept> { typedef gtl_no type; }; //equivalence template <typename polygon_set_type_1, typename polygon_set_type_2> typename enable_if< typename gtl_and_3< typename is_polygon_90_set_type<polygon_set_type_1>::type, typename is_polygon_90_set_type<polygon_set_type_2>::type, typename are_not_both_rectangle_concept<typename geometry_concept<polygon_set_type_1>::type, typename geometry_concept<polygon_set_type_2>::type>::type>::type, bool>::type equivalence(const polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { polygon_90_set_data<typename polygon_90_set_traits<polygon_set_type_1>::coordinate_type> ps1; assign(ps1, lvalue); polygon_90_set_data<typename polygon_90_set_traits<polygon_set_type_2>::coordinate_type> ps2; assign(ps2, rvalue); return ps1 == ps2; } //get rectangle tiles (slicing orientation is vertical) template <typename output_container_type, typename polygon_set_type> typename enable_if< typename gtl_if<typename is_polygon_90_set_type<polygon_set_type>::type>::type, void>::type get_rectangles(output_container_type& output, const polygon_set_type& polygon_set) { clean(polygon_set); polygon_90_set_data<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> ps(VERTICAL); assign(ps, polygon_set); ps.get_rectangles(output); } //get rectangle tiles template <typename output_container_type, typename polygon_set_type> typename enable_if< typename gtl_if<typename is_polygon_90_set_type<polygon_set_type>::type>::type, void>::type get_rectangles(output_container_type& output, const polygon_set_type& polygon_set, orientation_2d slicing_orientation) { clean(polygon_set); polygon_90_set_data<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> ps; assign(ps, polygon_set); ps.get_rectangles(output, slicing_orientation); } //get: min_rectangles max_rectangles template <typename output_container_type, typename polygon_set_type> typename enable_if <typename gtl_and< typename is_polygon_90_set_type<polygon_set_type>::type, typename gtl_same_type<rectangle_concept, typename geometry_concept <typename std::iterator_traits <typename output_container_type::iterator>::value_type>::type>::type>::type, void>::type get_max_rectangles(output_container_type& output, const polygon_set_type& polygon_set) { std::vector<rectangle_data<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> > rects; assign(rects, polygon_set); MaxCover<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::getMaxCover(output, rects, scanline_orientation(polygon_set)); } //clear template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, void>::type clear(polygon_set_type& polygon_set) { polygon_90_set_data<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> ps(scanline_orientation(polygon_set)); assign(polygon_set, ps); } //empty template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, bool>::type empty(const polygon_set_type& polygon_set) { if(clean(polygon_set)) return begin_90_set_data(polygon_set) == end_90_set_data(polygon_set); polygon_90_set_data<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> ps; assign(ps, polygon_set); ps.clean(); return ps.empty(); } //extents template <typename polygon_set_type, typename rectangle_type> typename enable_if <typename gtl_and< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, bool>::type extents(rectangle_type& extents_rectangle, const polygon_set_type& polygon_set) { typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; polygon_90_set_data<Unit> ps; assign(ps, polygon_set); return ps.extents(extents_rectangle); } //area template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::manhattan_area_type>::type area(const polygon_set_type& polygon_set) { typedef rectangle_data<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> rectangle_type; typedef typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::manhattan_area_type area_type; std::vector<rectangle_type> rects; assign(rects, polygon_set); area_type retval = (area_type)0; for(std::size_t i = 0; i < rects.size(); ++i) { retval += (area_type)area(rects[i]); } return retval; } //interact template <typename polygon_set_type_1, typename polygon_set_type_2> typename enable_if <typename gtl_and< typename is_mutable_polygon_90_set_type<polygon_set_type_1>::type, typename is_mutable_polygon_90_set_type<polygon_set_type_2>::type>::type, polygon_set_type_1>::type& interact(polygon_set_type_1& polygon_set_1, const polygon_set_type_2& polygon_set_2) { typedef typename polygon_90_set_traits<polygon_set_type_1>::coordinate_type Unit; polygon_90_set_data<Unit> ps(scanline_orientation(polygon_set_2)); polygon_90_set_data<Unit> ps2(ps); ps.insert(polygon_set_1); ps2.insert(polygon_set_2); ps.interact(ps2); assign(polygon_set_1, ps); return polygon_set_1; } //self_intersect template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & self_intersect(polygon_set_type& polygon_set) { typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; polygon_90_set_data<Unit> ps; assign(ps, polygon_set); ps.self_intersect(); assign(polygon_set, ps); return polygon_set; } //self_xor template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & self_xor(polygon_set_type& polygon_set) { typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; polygon_90_set_data<Unit> ps; assign(ps, polygon_set); ps.self_xor(); assign(polygon_set, ps); return polygon_set; } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & bloat(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { return bloat(polygon_set, bloating, bloating, bloating, bloating); } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & bloat(polygon_set_type& polygon_set, orientation_2d orient, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { if(orient == orientation_2d(HORIZONTAL)) return bloat(polygon_set, bloating, bloating, 0, 0); return bloat(polygon_set, 0, 0, bloating, bloating); } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & bloat(polygon_set_type& polygon_set, orientation_2d orient, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type low_bloating, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type high_bloating) { if(orient == orientation_2d(HORIZONTAL)) return bloat(polygon_set, low_bloating, high_bloating, 0, 0); return bloat(polygon_set, 0, 0, low_bloating, high_bloating); } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & bloat(polygon_set_type& polygon_set, direction_2d dir, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { if(dir == direction_2d(EAST)) return bloat(polygon_set, 0, bloating, 0, 0); if(dir == direction_2d(WEST)) return bloat(polygon_set, bloating, 0, 0, 0); if(dir == direction_2d(SOUTH)) return bloat(polygon_set, 0, 0, bloating, 0); return bloat(polygon_set, 0, 0, 0, bloating); } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & bloat(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type west_bloating, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type east_bloating, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type south_bloating, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type north_bloating) { typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; polygon_90_set_data<Unit> ps; assign(ps, polygon_set); ps.bloat(west_bloating, east_bloating, south_bloating, north_bloating); ps.clean(); assign(polygon_set, ps); return polygon_set; } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & shrink(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type shrinking) { return shrink(polygon_set, shrinking, shrinking, shrinking, shrinking); } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & shrink(polygon_set_type& polygon_set, orientation_2d orient, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type shrinking) { if(orient == orientation_2d(HORIZONTAL)) return shrink(polygon_set, shrinking, shrinking, 0, 0); return shrink(polygon_set, 0, 0, shrinking, shrinking); } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & shrink(polygon_set_type& polygon_set, orientation_2d orient, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type low_shrinking, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type high_shrinking) { if(orient == orientation_2d(HORIZONTAL)) return shrink(polygon_set, low_shrinking, high_shrinking, 0, 0); return shrink(polygon_set, 0, 0, low_shrinking, high_shrinking); } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & shrink(polygon_set_type& polygon_set, direction_2d dir, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type shrinking) { if(dir == direction_2d(EAST)) return shrink(polygon_set, 0, shrinking, 0, 0); if(dir == direction_2d(WEST)) return shrink(polygon_set, shrinking, 0, 0, 0); if(dir == direction_2d(SOUTH)) return shrink(polygon_set, 0, 0, shrinking, 0); return shrink(polygon_set, 0, 0, 0, shrinking); } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & shrink(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type west_shrinking, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type east_shrinking, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type south_shrinking, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type north_shrinking) { typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; polygon_90_set_data<Unit> ps; assign(ps, polygon_set); ps.shrink(west_shrinking, east_shrinking, south_shrinking, north_shrinking); ps.clean(); assign(polygon_set, ps); return polygon_set; } template <typename polygon_set_type, typename coord_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & resize(polygon_set_type& polygon_set, coord_type resizing) { if(resizing > 0) { return bloat(polygon_set, resizing); } if(resizing < 0) { return shrink(polygon_set, -resizing); } return polygon_set; } //positive or negative values allow for any and all directions of sizing template <typename polygon_set_type, typename coord_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & resize(polygon_set_type& polygon_set, coord_type west, coord_type east, coord_type south, coord_type north) { typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; polygon_90_set_data<Unit> ps; assign(ps, polygon_set); ps.resize(west, east, south, north); assign(polygon_set, ps); return polygon_set; } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & grow_and(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { return grow_and(polygon_set, bloating, bloating, bloating, bloating); } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & grow_and(polygon_set_type& polygon_set, orientation_2d orient, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { if(orient == orientation_2d(HORIZONTAL)) return grow_and(polygon_set, bloating, bloating, 0, 0); return grow_and(polygon_set, 0, 0, bloating, bloating); } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & grow_and(polygon_set_type& polygon_set, orientation_2d orient, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type low_bloating, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type high_bloating) { if(orient == orientation_2d(HORIZONTAL)) return grow_and(polygon_set, low_bloating, high_bloating, 0, 0); return grow_and(polygon_set, 0, 0, low_bloating, high_bloating); } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & grow_and(polygon_set_type& polygon_set, direction_2d dir, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { if(dir == direction_2d(EAST)) return grow_and(polygon_set, 0, bloating, 0, 0); if(dir == direction_2d(WEST)) return grow_and(polygon_set, bloating, 0, 0, 0); if(dir == direction_2d(SOUTH)) return grow_and(polygon_set, 0, 0, bloating, 0); return grow_and(polygon_set, 0, 0, 0, bloating); } template <typename polygon_set_type> typename enable_if< typename gtl_if<typename is_mutable_polygon_90_set_type<polygon_set_type>::type>::type, polygon_set_type>::type & grow_and(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type west_bloating, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type east_bloating, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type south_bloating, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type north_bloating) { typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; std::vector<polygon_90_data<Unit> > polys; assign(polys, polygon_set); clear(polygon_set); polygon_90_set_data<Unit> ps(scanline_orientation(polygon_set)); for(std::size_t i = 0; i < polys.size(); ++i) { polygon_90_set_data<Unit> tmpPs(scanline_orientation(polygon_set)); tmpPs.insert(polys[i]); bloat(tmpPs, west_bloating, east_bloating, south_bloating, north_bloating); tmpPs.clean(); //apply implicit OR on tmp polygon set ps.insert(tmpPs); } self_intersect(ps); assign(polygon_set, ps); return polygon_set; } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & scale_up(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> ::unsigned_area_type factor) { typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; polygon_90_set_data<Unit> ps; assign(ps, polygon_set); ps.scale_up(factor); assign(polygon_set, ps); return polygon_set; } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & scale_down(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> ::unsigned_area_type factor) { typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; polygon_90_set_data<Unit> ps; assign(ps, polygon_set); ps.scale_down(factor); assign(polygon_set, ps); return polygon_set; } template <typename polygon_set_type, typename scaling_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & scale(polygon_set_type& polygon_set, const scaling_type& scaling) { typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; polygon_90_set_data<Unit> ps; assign(ps, polygon_set); ps.scale(scaling); assign(polygon_set, ps); return polygon_set; } struct y_p_s_move : gtl_yes {}; //move template <typename polygon_set_type> typename enable_if< typename gtl_and<y_p_s_move, typename gtl_if<typename is_mutable_polygon_90_set_type<polygon_set_type>::type>::type>::type, polygon_set_type>::type & move(polygon_set_type& polygon_set, orientation_2d orient, typename polygon_90_set_traits<polygon_set_type>::coordinate_type displacement) { if(orient == HORIZONTAL) return move(polygon_set, displacement, 0); else return move(polygon_set, 0, displacement); } struct y_p_s_move2 : gtl_yes {}; template <typename polygon_set_type> typename enable_if< typename gtl_and<y_p_s_move2, typename gtl_if<typename is_mutable_polygon_90_set_type<polygon_set_type>::type>::type>::type, polygon_set_type>::type & move(polygon_set_type& polygon_set, typename polygon_90_set_traits<polygon_set_type>::coordinate_type x_displacement, typename polygon_90_set_traits<polygon_set_type>::coordinate_type y_displacement) { typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; polygon_90_set_data<Unit> ps; assign(ps, polygon_set); ps.move(x_displacement, y_displacement); ps.clean(); assign(polygon_set, ps); return polygon_set; } //transform template <typename polygon_set_type, typename transformation_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & transform(polygon_set_type& polygon_set, const transformation_type& transformation) { typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; polygon_90_set_data<Unit> ps; assign(ps, polygon_set); ps.transform(transformation); ps.clean(); assign(polygon_set, ps); return polygon_set; typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; } //keep template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, polygon_set_type>::type & keep(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type min_area, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type max_area, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type min_width, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type max_width, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type min_height, typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type max_height) { typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; typedef typename coordinate_traits<Unit>::unsigned_area_type uat; std::list<polygon_90_data<Unit> > polys; assign(polys, polygon_set); clear(polygon_set); typename std::list<polygon_90_data<Unit> >::iterator itr_nxt; for(typename std::list<polygon_90_data<Unit> >::iterator itr = polys.begin(); itr != polys.end(); itr = itr_nxt){ itr_nxt = itr; ++itr_nxt; rectangle_data<Unit> bbox; extents(bbox, *itr); uat pwidth = delta(bbox, HORIZONTAL); if(pwidth > min_width && pwidth <= max_width){ uat pheight = delta(bbox, VERTICAL); if(pheight > min_height && pheight <= max_height){ uat parea = area(*itr); if(parea <= max_area && parea >= min_area) { continue; } } } polys.erase(itr); } assign(polygon_set, polys); return polygon_set; } } } #include "detail/polygon_90_set_view.hpp" #endif segment_data.hpp 0000644 00000005324 15125572616 0007726 0 ustar 00 // Boost.Polygon library segment_data.hpp header file // Copyright (c) Intel Corporation 2008. // Copyright (c) 2008-2012 Simonson Lucanus. // Copyright (c) 2012-2012 Andrii Sydorchuk. // See http://www.boost.org for updates, documentation, and revision history. // Use, modification and distribution is 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_SEGMENT_DATA_HPP #define BOOST_POLYGON_SEGMENT_DATA_HPP #include "isotropy.hpp" #include "segment_concept.hpp" namespace boost { namespace polygon { template <typename T> class segment_data { public: typedef T coordinate_type; typedef point_data<T> point_type; segment_data() #ifndef BOOST_POLYGON_MSVC : points_() #endif {} segment_data(const point_type& low, const point_type& high) { points_[LOW] = low; points_[HIGH] = high; } segment_data(const segment_data& that) { points_[0] = that.points_[0]; points_[1] = that.points_[1]; } segment_data& operator=(const segment_data& that) { points_[0] = that.points_[0]; points_[1] = that.points_[1]; return *this; } template <typename SegmentType> segment_data& operator=(const SegmentType& that) { assign(*this, that); return *this; } point_type get(direction_1d dir) const { return points_[dir.to_int()]; } void set(direction_1d dir, const point_type& point) { points_[dir.to_int()] = point; } point_type low() const { return points_[LOW]; } segment_data& low(const point_type& point) { points_[LOW] = point; return *this; } point_type high() const { return points_[HIGH]; } segment_data& high(const point_type& point) { points_[HIGH] = point; return *this; } bool operator==(const segment_data& that) const { return (points_[0] == that.points_[0]) && (points_[1] == that.points_[1]); } bool operator!=(const segment_data& that) const { return (points_[0] != that.points_[0]) || (points_[1] != that.points_[1]); } bool operator<(const segment_data& that) const { if (points_[0] != that.points_[0]) { return points_[0] < that.points_[0]; } return points_[1] < that.points_[1]; } bool operator<=(const segment_data& that) const { return !(that < *this); } bool operator>(const segment_data& that) const { return that < *this; } bool operator>=(const segment_data& that) const { return !((*this) < that); } private: point_type points_[2]; }; template <typename CType> struct geometry_concept<segment_data<CType> > { typedef segment_concept type; }; } // polygon } // boost #endif // BOOST_POLYGON_SEGMENT_DATA_HPP rectangle_concept.hpp 0000644 00000143322 15125572616 0010753 0 ustar 00 /* 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_RECTANGLE_CONCEPT_HPP #define BOOST_POLYGON_RECTANGLE_CONCEPT_HPP #include "isotropy.hpp" //point #include "point_data.hpp" #include "point_traits.hpp" #include "point_concept.hpp" //interval #include "interval_data.hpp" #include "interval_traits.hpp" #include "interval_concept.hpp" #include "rectangle_data.hpp" #include "rectangle_traits.hpp" namespace boost { namespace polygon{ struct rectangle_concept {}; template <typename T> struct is_rectangle_concept { typedef gtl_no type; }; template <> struct is_rectangle_concept<rectangle_concept> { typedef gtl_yes type; }; template <typename T> struct is_mutable_rectangle_concept { typedef gtl_no type; }; template <> struct is_mutable_rectangle_concept<rectangle_concept> { typedef gtl_yes type; }; template <> struct geometry_domain<rectangle_concept> { typedef manhattan_domain type; }; template <typename T, typename CT> struct rectangle_interval_type_by_concept { typedef void type; }; template <typename T> struct rectangle_interval_type_by_concept<T, gtl_yes> { typedef typename rectangle_traits<T>::interval_type type; }; template <typename T> struct rectangle_interval_type { typedef typename rectangle_interval_type_by_concept<T, typename is_rectangle_concept<typename geometry_concept<T>::type>::type>::type type; }; template <typename T, typename CT> struct rectangle_coordinate_type_by_concept { typedef void type; }; template <typename T> struct rectangle_coordinate_type_by_concept<T, gtl_yes> { typedef typename rectangle_traits<T>::coordinate_type type; }; template <typename T> struct rectangle_coordinate_type { typedef typename rectangle_coordinate_type_by_concept<T, typename is_rectangle_concept<typename geometry_concept<T>::type>::type>::type type; }; template <typename T, typename CT> struct rectangle_difference_type_by_concept { typedef void type; }; template <typename T> struct rectangle_difference_type_by_concept<T, gtl_yes> { typedef typename coordinate_traits<typename rectangle_traits<T>::coordinate_type>::coordinate_difference type; }; template <typename T> struct rectangle_difference_type { typedef typename rectangle_difference_type_by_concept< T, typename is_rectangle_concept<typename geometry_concept<T>::type>::type>::type type; }; template <typename T, typename CT> struct rectangle_distance_type_by_concept { typedef void type; }; template <typename T> struct rectangle_distance_type_by_concept<T, gtl_yes> { typedef typename coordinate_traits<typename rectangle_coordinate_type<T>::type>::coordinate_distance type; }; template <typename T> struct rectangle_distance_type { typedef typename rectangle_distance_type_by_concept< T, typename is_rectangle_concept<typename geometry_concept<T>::type>::type>::type type; }; struct y_r_get_interval : gtl_yes {}; template <typename T> typename enable_if< typename gtl_and<y_r_get_interval, typename is_rectangle_concept<typename geometry_concept<T>::type>::type>::type, typename rectangle_interval_type<T>::type>::type get(const T& rectangle, orientation_2d orient) { return rectangle_traits<T>::get(rectangle, orient); } struct y_r_h : gtl_yes {}; template <typename T> typename enable_if< typename gtl_and<y_r_h, typename is_rectangle_concept<typename geometry_concept<T>::type>::type>::type, typename rectangle_interval_type<T>::type>::type horizontal(const T& rectangle) { return rectangle_traits<T>::get(rectangle, HORIZONTAL); } struct y_r_v : gtl_yes {}; template <typename T> typename enable_if< typename gtl_and<y_r_v, typename is_rectangle_concept<typename geometry_concept<T>::type>::type>::type, typename rectangle_interval_type<T>::type>::type vertical(const T& rectangle) { return rectangle_traits<T>::get(rectangle, VERTICAL); } struct y_r_set : gtl_yes {}; template <orientation_2d_enum orient, typename T, typename T2> typename enable_if< typename gtl_and_3<y_r_set, typename is_mutable_rectangle_concept<typename geometry_concept<T>::type>::type, typename is_interval_concept<typename geometry_concept<T2>::type>::type>::type, void>::type set(T& rectangle, const T2& interval) { rectangle_mutable_traits<T>::set(rectangle, orient, interval); } struct y_r_set2 : gtl_yes {}; template <typename T, typename T2> typename enable_if< typename gtl_and_3<y_r_set2, typename is_mutable_rectangle_concept<typename geometry_concept<T>::type>::type, typename is_interval_concept<typename geometry_concept<T2>::type>::type>::type, void>::type set(T& rectangle, orientation_2d orient, const T2& interval) { rectangle_mutable_traits<T>::set(rectangle, orient, interval); } struct y_r_h2 : gtl_yes {}; template <typename T, typename T2> typename enable_if< typename gtl_and_3<y_r_h2, typename is_mutable_rectangle_concept<typename geometry_concept<T>::type>::type, typename is_interval_concept<typename geometry_concept<T2>::type>::type>::type, void>::type horizontal(T& rectangle, const T2& interval) { rectangle_mutable_traits<T>::set(rectangle, HORIZONTAL, interval); } struct y_r_v2 : gtl_yes {}; template <typename T, typename T2> typename enable_if< typename gtl_and_3<y_r_v2, typename is_mutable_rectangle_concept<typename geometry_concept<T>::type>::type, typename is_interval_concept<typename geometry_concept<T2>::type>::type>::type, void>::type vertical(T& rectangle, const T2& interval) { rectangle_mutable_traits<T>::set(rectangle, VERTICAL, interval); } struct y_r_construct : gtl_yes {}; template <typename T, typename T2, typename T3> typename enable_if< typename gtl_and<y_r_construct, typename is_mutable_rectangle_concept<typename geometry_concept<T>::type>::type>::type, T>::type construct(const T2& interval_horizontal, const T3& interval_vertical) { return rectangle_mutable_traits<T>::construct(interval_horizontal, interval_vertical); } struct y_r_construct2 : gtl_yes {}; template <typename T, typename coord_type> typename enable_if< typename gtl_and<y_r_construct2, typename is_mutable_rectangle_concept<typename geometry_concept<T>::type>::type>::type, T>::type construct(coord_type xl, coord_type yl, coord_type xh, coord_type yh) { return rectangle_mutable_traits<T>::construct(interval_data<coord_type>(xl, xh), interval_data<coord_type>(yl, yh)); } struct y_r_cconstruct : gtl_yes {}; template <typename T, typename T2> typename enable_if< typename gtl_and_3<y_r_cconstruct, typename is_mutable_rectangle_concept<typename geometry_concept<T>::type>::type, typename is_rectangle_concept<typename geometry_concept<T2>::type>::type>::type, T>::type copy_construct(const T2& rectangle) { return construct<T> (get(rectangle, HORIZONTAL), get(rectangle, VERTICAL)); } struct y_r_assign : gtl_yes {}; template <typename rectangle_type_1, typename rectangle_type_2> typename enable_if< typename gtl_and_3< y_r_assign, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, rectangle_type_1>::type & assign(rectangle_type_1& lvalue, const rectangle_type_2& rvalue) { set(lvalue, HORIZONTAL, get(rvalue, HORIZONTAL)); set(lvalue, VERTICAL, get(rvalue, VERTICAL)); return lvalue; } struct y_r_equiv : gtl_yes {}; template <typename T, typename T2> typename enable_if< typename gtl_and_3< y_r_equiv, typename is_rectangle_concept<typename geometry_concept<T>::type>::type, typename is_rectangle_concept<typename geometry_concept<T2>::type>::type>::type, bool>::type equivalence(const T& rect1, const T2& rect2) { return equivalence(get(rect1, HORIZONTAL), get(rect2, HORIZONTAL)) && equivalence(get(rect1, VERTICAL), get(rect2, VERTICAL)); } struct y_r_get : gtl_yes {}; template <typename rectangle_type> typename enable_if< typename gtl_and<y_r_get, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, typename rectangle_coordinate_type<rectangle_type>::type>::type get(const rectangle_type& rectangle, orientation_2d orient, direction_1d dir) { return get(rectangle_traits<rectangle_type>::get(rectangle, orient), dir); } struct y_r_set3 : gtl_yes {}; template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_set3, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, void>::type set(rectangle_type& rectangle, orientation_2d orient, direction_1d dir, typename rectangle_coordinate_type<rectangle_type>::type value) { typename rectangle_interval_type<rectangle_type>::type ivl = get(rectangle, orient); set(ivl, dir, value); set(rectangle, orient, ivl); } struct y_r_xl : gtl_yes {}; template <typename rectangle_type> typename enable_if< typename gtl_and<y_r_xl, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, typename rectangle_coordinate_type<rectangle_type>::type>::type xl(const rectangle_type& rectangle) { return get(rectangle, HORIZONTAL, LOW); } struct y_r_xl2 : gtl_yes {}; template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_xl2, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, void>::type xl(rectangle_type& rectangle, typename rectangle_coordinate_type<rectangle_type>::type value) { return set(rectangle, HORIZONTAL, LOW, value); } struct y_r_xh : gtl_yes {}; template <typename rectangle_type> typename enable_if< typename gtl_and<y_r_xh, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, typename rectangle_coordinate_type<rectangle_type>::type>::type xh(const rectangle_type& rectangle) { return get(rectangle, HORIZONTAL, HIGH); } struct y_r_xh2 : gtl_yes {}; template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_xh2, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, void>::type xh(rectangle_type& rectangle, typename rectangle_coordinate_type<rectangle_type>::type value) { return set(rectangle, HORIZONTAL, HIGH, value); } struct y_r_yl : gtl_yes {}; template <typename rectangle_type> typename enable_if< typename gtl_and<y_r_yl, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, typename rectangle_coordinate_type<rectangle_type>::type>::type yl(const rectangle_type& rectangle) { return get(rectangle, VERTICAL, LOW); } struct y_r_yl2 : gtl_yes {}; template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_yl2, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, void>::type yl(rectangle_type& rectangle, typename rectangle_coordinate_type<rectangle_type>::type value) { return set(rectangle, VERTICAL, LOW, value); } struct y_r_yh : gtl_yes {}; template <typename rectangle_type> typename enable_if< typename gtl_and<y_r_yh, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, typename rectangle_coordinate_type<rectangle_type>::type>::type yh(const rectangle_type& rectangle) { return get(rectangle, VERTICAL, HIGH); } struct y_r_yh2 : gtl_yes {}; template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_yh2, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, void>::type yh(rectangle_type& rectangle, typename rectangle_coordinate_type<rectangle_type>::type value) { return set(rectangle, VERTICAL, HIGH, value); } struct y_r_ll : gtl_yes {}; template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_ll, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, point_data<typename rectangle_coordinate_type<rectangle_type>::type> >::type ll(const rectangle_type& rectangle) { return point_data<typename rectangle_coordinate_type<rectangle_type>::type> (xl(rectangle), yl(rectangle)); } struct y_r_lr : gtl_yes {}; template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_lr, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, point_data<typename rectangle_coordinate_type<rectangle_type>::type> >::type lr(const rectangle_type& rectangle) { return point_data<typename rectangle_coordinate_type<rectangle_type>::type> (xh(rectangle), yl(rectangle)); } struct y_r_ul : gtl_yes {}; template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_ul, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, point_data<typename rectangle_coordinate_type<rectangle_type>::type> >::type ul(const rectangle_type& rectangle) { return point_data<typename rectangle_coordinate_type<rectangle_type>::type> (xl(rectangle), yh(rectangle)); } struct y_r_ur : gtl_yes {}; template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_ur, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, point_data<typename rectangle_coordinate_type<rectangle_type>::type> >::type ur(const rectangle_type& rectangle) { return point_data<typename rectangle_coordinate_type<rectangle_type>::type> (xh(rectangle), yh(rectangle)); } struct y_r_contains : gtl_yes {}; template <typename rectangle_type, typename rectangle_type_2> typename enable_if< typename gtl_and_3<y_r_contains, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, bool>::type contains(const rectangle_type& rectangle, const rectangle_type_2 rectangle_contained, bool consider_touch = true) { return contains(horizontal(rectangle), horizontal(rectangle_contained), consider_touch) && contains(vertical(rectangle), vertical(rectangle_contained), consider_touch); } struct y_r_contains2 : gtl_yes {}; template <typename rectangle_type, typename point_type> typename enable_if< typename gtl_and_3<y_r_contains2, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, bool>::type contains(const rectangle_type& rectangle, const point_type point_contained, bool consider_touch = true) { return contains(horizontal(rectangle), x(point_contained), consider_touch) && contains(vertical(rectangle), y(point_contained), consider_touch); } struct y_r_set_points : gtl_yes {}; // set all four coordinates based upon two points template <typename rectangle_type, typename point_type_1, typename point_type_2> typename enable_if< typename gtl_and_4< y_r_set_points, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, typename is_point_concept<typename geometry_concept<point_type_1>::type>::type, typename is_point_concept<typename geometry_concept<point_type_2>::type>::type>::type, rectangle_type>::type & set_points(rectangle_type& rectangle, const point_type_1& p1, const point_type_2& p2) { typedef typename rectangle_coordinate_type<rectangle_type>::type Unit; Unit x1(x(p1)); Unit x2(x(p2)); Unit y1(y(p1)); Unit y2(y(p2)); horizontal(rectangle, construct<typename rectangle_interval_type<rectangle_type>::type>(x1, x2)); vertical(rectangle, construct<typename rectangle_interval_type<rectangle_type>::type>(y1, y2)); return rectangle; } struct y_r_move : gtl_yes {}; // move rectangle by delta in orient template <typename rectangle_type> typename enable_if< typename gtl_and<y_r_move, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, rectangle_type>::type & move(rectangle_type& rectangle, orientation_2d orient, typename coordinate_traits<typename rectangle_coordinate_type<rectangle_type>::type>::coordinate_difference delta) { typename rectangle_interval_type<rectangle_type>::type ivl = get(rectangle, orient); move(ivl, delta); set(rectangle, orient, ivl); return rectangle; } struct y_r_convolve : gtl_yes {}; // convolve this with b template <typename rectangle_type_1, typename rectangle_type_2> typename enable_if< typename gtl_and_3< y_r_convolve, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, rectangle_type_1>::type & convolve(rectangle_type_1& rectangle, const rectangle_type_2& convolution_rectangle) { typename rectangle_interval_type<rectangle_type_1>::type ivl = horizontal(rectangle); horizontal(rectangle, convolve(ivl, horizontal(convolution_rectangle))); ivl = vertical(rectangle); vertical(rectangle, convolve(ivl, vertical(convolution_rectangle))); return rectangle; } struct y_r_deconvolve : gtl_yes {}; // deconvolve this with b template <typename rectangle_type_1, typename rectangle_type_2> typename enable_if< typename gtl_and_3< y_r_deconvolve, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, rectangle_type_1>::type & deconvolve(rectangle_type_1& rectangle, const rectangle_type_2& convolution_rectangle) { typename rectangle_interval_type<rectangle_type_1>::type ivl = horizontal(rectangle); horizontal(rectangle, deconvolve(ivl, horizontal(convolution_rectangle))); ivl = vertical(rectangle); vertical(rectangle, deconvolve(ivl, vertical(convolution_rectangle))); return rectangle; } struct y_r_reconvolve : gtl_yes {}; // reflectedConvolve this with b template <typename rectangle_type_1, typename rectangle_type_2> typename enable_if< typename gtl_and_3<y_r_reconvolve, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, rectangle_type_1>::type & reflected_convolve(rectangle_type_1& rectangle, const rectangle_type_2& convolution_rectangle) { typename rectangle_interval_type<rectangle_type_1>::type ivl = horizontal(rectangle); horizontal(rectangle, reflected_convolve(ivl, horizontal(convolution_rectangle))); ivl = vertical(rectangle); vertical(rectangle, reflected_convolve(ivl, vertical(convolution_rectangle))); return rectangle; } struct y_r_redeconvolve : gtl_yes {}; // reflectedDeconvolve this with b // deconvolve this with b template <typename rectangle_type_1, typename rectangle_type_2> typename enable_if< typename gtl_and_3<y_r_redeconvolve, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, rectangle_type_1>::type & reflected_deconvolve(rectangle_type_1& rectangle, const rectangle_type_2& convolution_rectangle) { typename rectangle_interval_type<rectangle_type_1>::type ivl = horizontal(rectangle); horizontal(rectangle, reflected_deconvolve(ivl, horizontal(convolution_rectangle))); ivl = vertical(rectangle); vertical(rectangle, reflected_deconvolve(ivl, vertical(convolution_rectangle))); return rectangle; } struct y_r_convolve2 : gtl_yes {}; // convolve with point template <typename rectangle_type, typename point_type> typename enable_if< typename gtl_and_3<y_r_convolve2, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, rectangle_type>::type & convolve(rectangle_type& rectangle, const point_type& convolution_point) { typename rectangle_interval_type<rectangle_type>::type ivl = horizontal(rectangle); horizontal(rectangle, convolve(ivl, x(convolution_point))); ivl = vertical(rectangle); vertical(rectangle, convolve(ivl, y(convolution_point))); return rectangle; } struct y_r_deconvolve2 : gtl_yes {}; // deconvolve with point template <typename rectangle_type, typename point_type> typename enable_if< typename gtl_and_3<y_r_deconvolve2, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, rectangle_type>::type & deconvolve(rectangle_type& rectangle, const point_type& convolution_point) { typename rectangle_interval_type<rectangle_type>::type ivl = horizontal(rectangle); horizontal(rectangle, deconvolve(ivl, x(convolution_point))); ivl = vertical(rectangle); vertical(rectangle, deconvolve(ivl, y(convolution_point))); return rectangle; } struct y_r_delta : gtl_yes {}; // get the magnitude of the interval range depending on orient template <typename rectangle_type> typename enable_if< typename gtl_and<y_r_delta, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, typename rectangle_difference_type<rectangle_type>::type>::type delta(const rectangle_type& rectangle, orientation_2d orient) { return delta(get(rectangle, orient)); } struct y_r_area : gtl_yes {}; // get the area of the rectangle template <typename rectangle_type> typename enable_if< typename gtl_and<y_r_area, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, typename coordinate_traits<typename rectangle_coordinate_type<rectangle_type>::type>::manhattan_area_type>::type area(const rectangle_type& rectangle) { typedef typename coordinate_traits<typename rectangle_coordinate_type<rectangle_type>::type>::manhattan_area_type area_type; return (area_type)delta(rectangle, HORIZONTAL) * (area_type)delta(rectangle, VERTICAL); } struct y_r_go : gtl_yes {}; // returns the orientation of the longest side template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_go, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, orientation_2d>::type guess_orientation(const rectangle_type& rectangle) { return delta(rectangle, HORIZONTAL) >= delta(rectangle, VERTICAL) ? HORIZONTAL : VERTICAL; } struct y_r_half_p : gtl_yes {}; // get the half perimeter of the rectangle template <typename rectangle_type> typename enable_if< typename gtl_and<y_r_half_p, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, typename rectangle_difference_type<rectangle_type>::type>::type half_perimeter(const rectangle_type& rectangle) { return delta(rectangle, HORIZONTAL) + delta(rectangle, VERTICAL); } struct y_r_perimeter : gtl_yes {}; // get the perimeter of the rectangle template <typename rectangle_type> typename enable_if< typename gtl_and<y_r_perimeter, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, typename rectangle_difference_type<rectangle_type>::type>::type perimeter(const rectangle_type& rectangle) { return 2 * half_perimeter(rectangle); } struct y_r_intersects : gtl_yes {}; // check if Rectangle b intersects `this` Rectangle // [in] b Rectangle that will be checked // [in] considerTouch If true, return true even if b touches the boundary // [ret] . true if `t` intersects b template <typename rectangle_type_1, typename rectangle_type_2> typename enable_if< typename gtl_and_3<y_r_intersects, typename is_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, bool>::type intersects(const rectangle_type_1& rectangle, const rectangle_type_2& b, bool consider_touch = true) { return intersects(horizontal(rectangle), horizontal(b), consider_touch) && intersects(vertical(rectangle), vertical(b), consider_touch); } struct y_r_b_intersect : gtl_yes {}; // Check if boundaries of Rectangle b and `this` Rectangle intersect // [in] b Rectangle that will be checked // [in] considerTouch If true, return true even if p is on the foundary // [ret] . true if `t` contains p template <typename rectangle_type_1, typename rectangle_type_2> typename enable_if< typename gtl_and_3<y_r_b_intersect, typename is_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, bool>::type boundaries_intersect(const rectangle_type_1& rectangle, const rectangle_type_2& b, bool consider_touch = true) { return (intersects(rectangle, b, consider_touch) && !(contains(rectangle, b, !consider_touch)) && !(contains(b, rectangle, !consider_touch))); } struct y_r_b_abuts : gtl_yes {}; // check if b is touching 'this' on the end specified by dir template <typename rectangle_type_1, typename rectangle_type_2> typename enable_if< typename gtl_and_3<y_r_b_abuts, typename is_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, bool>::type abuts(const rectangle_type_1& rectangle, const rectangle_type_2& b, direction_2d dir) { return abuts(get(rectangle, orientation_2d(dir)), get(b, orientation_2d(dir)), direction_1d(dir)) && intersects(get(rectangle, orientation_2d(dir).get_perpendicular()), get(b, orientation_2d(dir).get_perpendicular()), true); } struct y_r_b_abuts2 : gtl_yes {}; // check if they are touching in the given orientation template <typename rectangle_type_1, typename rectangle_type_2> typename enable_if< typename gtl_and_3<y_r_b_abuts2, typename is_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, bool>::type abuts(const rectangle_type_1& rectangle, const rectangle_type_2& b, orientation_2d orient) { return abuts(get(rectangle, orient), get(b, orient)) && intersects(get(rectangle, orient.get_perpendicular()), get(b, orient.get_perpendicular()), true); } struct y_r_b_abuts3 : gtl_yes {}; // check if they are touching but not overlapping template <typename rectangle_type_1, typename rectangle_type_2> typename enable_if< typename gtl_and_3<y_r_b_abuts3, typename is_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, bool>::type abuts(const rectangle_type_1& rectangle, const rectangle_type_2& b) { return abuts(rectangle, b, HORIZONTAL) || abuts(rectangle, b, VERTICAL); } struct y_r_b_intersect2 : gtl_yes {}; // intersect rectangle with interval on orient template <typename rectangle_type, typename interval_type> typename enable_if< typename gtl_and_3<y_r_b_intersect2, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, typename is_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, bool>::type intersect(rectangle_type& rectangle, const interval_type& b, orientation_2d orient, bool consider_touch = true) { typename rectangle_interval_type<rectangle_type>::type ivl = get(rectangle, orient); if(intersect(ivl, b, consider_touch)) { set(rectangle, orient, ivl); return true; } return false; } struct y_r_b_intersect3 : gtl_yes {}; // clip rectangle to b template <typename rectangle_type_1, typename rectangle_type_2> typename enable_if< typename gtl_and_3<y_r_b_intersect3, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, bool>::type intersect(rectangle_type_1& rectangle, const rectangle_type_2& b, bool consider_touch = true) { if(intersects(rectangle, b)) { intersect(rectangle, horizontal(b), HORIZONTAL, consider_touch); intersect(rectangle, vertical(b), VERTICAL, consider_touch); return true; } return false; } struct y_r_g_intersect : gtl_yes {}; // Sets this to the generalized intersection of this and the given rectangle template <typename rectangle_type_1, typename rectangle_type_2> typename enable_if< typename gtl_and_3<y_r_g_intersect, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, rectangle_type_1>::type & generalized_intersect(rectangle_type_1& rectangle, const rectangle_type_2& b) { typename rectangle_interval_type<rectangle_type_1>::type ivl = get(rectangle, HORIZONTAL); generalized_intersect(ivl, horizontal(b)); horizontal(rectangle, ivl); ivl = vertical(rectangle); generalized_intersect(ivl, vertical(b)); vertical(rectangle, ivl); return rectangle; } struct y_r_bloat : gtl_yes {}; // bloat the interval specified by orient by bloating template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_bloat, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, rectangle_type>::type & bloat(rectangle_type& rectangle, orientation_2d orient, typename rectangle_coordinate_type<rectangle_type>::type bloating) { typename rectangle_interval_type<rectangle_type>::type ivl = get(rectangle, orient); bloat(ivl, bloating); set(rectangle, orient, ivl); return rectangle; } struct y_r_bloat2 : gtl_yes {}; // bloat the Rectangle by bloating template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_bloat2, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, rectangle_type>::type & bloat(rectangle_type& rectangle, typename rectangle_coordinate_type<rectangle_type>::type bloating) { bloat(rectangle, HORIZONTAL, bloating); return bloat(rectangle, VERTICAL, bloating); } struct y_r_bloat3 : gtl_yes {}; // bloat the interval cooresponding to orient by bloating in dir direction template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_bloat3, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, rectangle_type>::type & bloat(rectangle_type& rectangle, direction_2d dir, typename rectangle_coordinate_type<rectangle_type>::type bloating) { typename rectangle_interval_type<rectangle_type>::type ivl = get(rectangle, orientation_2d(dir)); bloat(ivl, direction_1d(dir), bloating); set(rectangle, orientation_2d(dir), ivl); return rectangle; } struct y_r_shrink : gtl_yes {}; // shrink the interval specified by orient by bloating template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_shrink, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, rectangle_type>::type & shrink(rectangle_type& rectangle, orientation_2d orient, typename rectangle_coordinate_type<rectangle_type>::type shrinking) { return bloat(rectangle, orient, -shrinking); } struct y_r_shrink2 : gtl_yes {}; // shrink the Rectangle by bloating template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_shrink2, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, rectangle_type>::type & shrink(rectangle_type& rectangle, typename rectangle_coordinate_type<rectangle_type>::type shrinking) { return bloat(rectangle, -shrinking); } struct y_r_shrink3 : gtl_yes {}; // shrink the interval cooresponding to orient by bloating in dir direction template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_shrink3, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, rectangle_type>::type & shrink(rectangle_type& rectangle, direction_2d dir, typename rectangle_coordinate_type<rectangle_type>::type shrinking) { return bloat(rectangle, dir, -shrinking); } struct y_r_encompass : gtl_yes {}; // encompass interval on orient template <typename rectangle_type, typename interval_type> typename enable_if<typename gtl_and_3< y_r_encompass, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, typename is_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, bool>::type encompass(rectangle_type& rectangle, const interval_type& b, orientation_2d orient) { typename rectangle_interval_type<rectangle_type>::type ivl = get(rectangle, orient); if(encompass(ivl, b)) { set(rectangle, orient, ivl); return true; } return false; } struct y_r_encompass2 : gtl_yes {}; // enlarge rectangle to encompass the Rectangle b template <typename rectangle_type_1, typename rectangle_type_2> typename enable_if< typename gtl_and_3< y_r_encompass2, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type >::type, bool>::type encompass(rectangle_type_1& rectangle, const rectangle_type_2& b) { //note that operator | is intentional because both should be called regardless return encompass(rectangle, horizontal(b), HORIZONTAL) | encompass(rectangle, vertical(b), VERTICAL); } struct y_r_encompass3 : gtl_yes {}; // enlarge rectangle to encompass the point b template <typename rectangle_type_1, typename point_type> typename enable_if<typename gtl_and_3< y_r_encompass3, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, bool>::type encompass(rectangle_type_1& rectangle, const point_type& b) { typename rectangle_interval_type<rectangle_type_1>::type hivl, vivl; hivl = horizontal(rectangle); vivl = vertical(rectangle); //note that operator | is intentional because both should be called regardless bool retval = encompass(hivl, x(b)) | encompass(vivl, y(b)); if(retval) { horizontal(rectangle, hivl); vertical(rectangle, vivl); } return retval; } struct y_r_center : gtl_yes {}; // returns the center of the rectangle template <typename point_type, typename rectangle_type> typename enable_if< typename gtl_and_3<y_r_center, typename is_mutable_point_concept<typename geometry_concept<point_type>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, bool>::type center(point_type& center_point, const rectangle_type& rectangle) { center_point = construct<point_type>(center(horizontal(rectangle)), center(vertical(rectangle))); return true; } struct y_r_get_corner : gtl_yes {}; template <typename point_type, typename rectangle_type> typename enable_if< typename gtl_and_3<y_r_get_corner, typename is_mutable_point_concept<typename geometry_concept<point_type>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, bool>::type get_corner(point_type& corner_point, const rectangle_type& rectangle, direction_2d direction_facing, direction_1d direction_turning) { typedef typename rectangle_coordinate_type<rectangle_type>::type Unit; Unit u1 = get(rectangle, direction_facing); Unit u2 = get(rectangle, direction_facing.turn(direction_turning)); if(orientation_2d(direction_facing).to_int()) std::swap(u1, u2); corner_point = construct<point_type>(u1, u2); return true; } struct y_r_get_half : gtl_yes {}; template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_get_half, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, rectangle_type>::type get_half(const rectangle_type& rectangle, direction_2d dir) { rectangle_type retval(rectangle); set(retval, orientation_2d(dir), get_half(get(rectangle, orientation_2d(dir)), direction_1d(dir))); return retval; } struct y_r_join_with : gtl_yes {}; template <typename rectangle_type_1, typename rectangle_type_2> typename enable_if< typename gtl_and_3<y_r_join_with, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, bool>::type join_with(rectangle_type_1& rectangle, const rectangle_type_2& b) { typedef typename rectangle_interval_type<rectangle_type_1>::type Interval1; typedef typename rectangle_interval_type<rectangle_type_2>::type Interval2; Interval1 hi1 = get(rectangle, HORIZONTAL); Interval1 vi1 = get(rectangle, VERTICAL); Interval2 hi2 = get(b, HORIZONTAL), vi2 = get(b, VERTICAL); Interval1 temp; if (equivalence(hi1, hi2) && join_with(vi1, vi2)) { vertical(rectangle, vi1); return true; } if (equivalence(vi1, vi2) && join_with(hi1, hi2)) { horizontal(rectangle, hi1); return true; } return false; } struct y_r_eda2 : gtl_yes {}; template <typename rectangle_type, typename point_type> typename enable_if< typename gtl_and_3<y_r_eda2, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, typename rectangle_difference_type<rectangle_type>::type>::type euclidean_distance(const rectangle_type& lvalue, const point_type& rvalue, orientation_2d orient) { return euclidean_distance(get(lvalue, orient), get(rvalue, orient)); } struct y_r_eda : gtl_yes {}; template <typename rectangle_type, typename rectangle_type_2> typename enable_if< typename gtl_and_3<y_r_eda, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, typename rectangle_difference_type<rectangle_type>::type>::type euclidean_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue, orientation_2d orient) { return euclidean_distance(get(lvalue, orient), get(rvalue, orient)); } struct y_r_sed : gtl_yes {}; template <typename rectangle_type, typename point_type> typename enable_if< typename gtl_and_3<y_r_sed, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, typename rectangle_difference_type<rectangle_type>::type>::type square_euclidean_distance(rectangle_type& lvalue, const point_type& rvalue) { typename coordinate_traits<typename rectangle_coordinate_type<rectangle_type>::type>::coordinate_difference xdist, ydist; xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); ydist = euclidean_distance(lvalue, rvalue, VERTICAL); return (xdist * xdist) + (ydist * ydist); } struct y_r_sed2 : gtl_yes {}; template <typename rectangle_type, typename rectangle_type_2> typename enable_if< typename gtl_and_3<y_r_sed2, typename is_rectangle_concept< typename geometry_concept<rectangle_type>::type>::type, typename is_rectangle_concept< typename geometry_concept<rectangle_type_2>::type>::type>::type, typename rectangle_difference_type<rectangle_type>::type>::type square_euclidean_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue) { typename coordinate_traits<typename rectangle_coordinate_type<rectangle_type>::type>::coordinate_difference xdist, ydist; xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); ydist = euclidean_distance(lvalue, rvalue, VERTICAL); return (xdist * xdist) + (ydist * ydist); } struct y_r_edist : gtl_yes {}; template <typename rectangle_type, typename point_type> typename enable_if< typename gtl_and_3<y_r_edist, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, typename rectangle_distance_type<rectangle_type>::type>::type euclidean_distance(rectangle_type& lvalue, const point_type& rvalue) { return std::sqrt((double)(square_euclidean_distance(lvalue, rvalue))); } struct y_r_edist2 : gtl_yes {}; template <typename rectangle_type, typename rectangle_type_2> typename enable_if< typename gtl_and_3<y_r_edist2, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, typename rectangle_distance_type<rectangle_type>::type>::type euclidean_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue) { double val = (int)square_euclidean_distance(lvalue, rvalue); return std::sqrt(val); } struct y_r_mdist : gtl_yes {}; template <typename rectangle_type, typename point_type> typename enable_if< typename gtl_and_3<y_r_mdist, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, typename rectangle_difference_type<rectangle_type>::type>::type manhattan_distance(rectangle_type& lvalue, const point_type& rvalue) { typename coordinate_traits<typename rectangle_coordinate_type<rectangle_type>::type>::coordinate_difference xdist, ydist; xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); ydist = euclidean_distance(lvalue, rvalue, VERTICAL); return xdist + ydist; } struct y_r_mdist2 : gtl_yes {}; template <typename rectangle_type, typename rectangle_type_2> typename enable_if< typename gtl_and_3<y_r_mdist2, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, typename rectangle_difference_type<rectangle_type>::type>::type manhattan_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue) { typename coordinate_traits<typename rectangle_coordinate_type<rectangle_type>::type>::coordinate_difference xdist, ydist; xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); ydist = euclidean_distance(lvalue, rvalue, VERTICAL); return xdist + ydist; } struct y_r_scale_up : gtl_yes {}; template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_scale_up, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, rectangle_type>::type & scale_up(rectangle_type& rectangle, typename coordinate_traits<typename rectangle_coordinate_type<rectangle_type>::type>::unsigned_area_type factor) { typename rectangle_interval_type<rectangle_type>::type h = horizontal(rectangle); horizontal(rectangle, scale_up(h, factor)); typename rectangle_interval_type<rectangle_type>::type v = vertical(rectangle); vertical(rectangle, scale_up(v, factor)); return rectangle; } struct y_r_scale_down : gtl_yes {}; template <typename rectangle_type> typename enable_if<typename gtl_and<y_r_scale_down, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, rectangle_type>::type & scale_down(rectangle_type& rectangle, typename coordinate_traits<typename rectangle_coordinate_type<rectangle_type>::type>::unsigned_area_type factor) { typename rectangle_interval_type<rectangle_type>::type h = horizontal(rectangle); horizontal(rectangle, scale_down(h, factor)); typename rectangle_interval_type<rectangle_type>::type v = vertical(rectangle); vertical(rectangle, scale_down(v, factor)); return rectangle; } struct y_r_scale : gtl_yes {}; template <typename rectangle_type, typename scaling_type> typename enable_if<typename gtl_and<y_r_scale, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, rectangle_type>::type & scale(rectangle_type& rectangle, const scaling_type& scaling) { point_data<typename rectangle_coordinate_type<rectangle_type>::type> llp(xl(rectangle), yl(rectangle)); point_data<typename rectangle_coordinate_type<rectangle_type>::type> urp(xl(rectangle), yl(rectangle)); scale(llp, scaling); scale(urp, scaling); set_points(rectangle, llp, urp); return rectangle; } struct y_r_transform : gtl_yes {}; template <typename rectangle_type, typename transformation_type> typename enable_if<typename gtl_and<y_r_transform, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, rectangle_type>::type & transform(rectangle_type& rectangle, const transformation_type& transformation) { point_data<typename rectangle_coordinate_type<rectangle_type>::type> llp(xl(rectangle), yl(rectangle)); point_data<typename rectangle_coordinate_type<rectangle_type>::type> urp(xh(rectangle), yh(rectangle)); transform(llp, transformation); transform(urp, transformation); set_points(rectangle, llp, urp); return rectangle; } template <typename rectangle_type_1, typename rectangle_type_2> class less_rectangle_concept { private: orientation_2d orient_; public: inline less_rectangle_concept(orientation_2d orient = VERTICAL) : orient_(orient) {} typename enable_if< typename gtl_and< typename is_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, bool>::type operator () (const rectangle_type_1& a, const rectangle_type_2& b) const { typedef typename rectangle_coordinate_type<rectangle_type_1>::type Unit; Unit vl1 = get(get(a, orient_), LOW); Unit vl2 = get(get(b, orient_), LOW); if(vl1 > vl2) return false; if(vl1 == vl2) { orientation_2d perp = orient_.get_perpendicular(); Unit hl1 = get(get(a, perp), LOW); Unit hl2 = get(get(b, perp), LOW); if(hl1 > hl2) return false; if(hl1 == hl2) { Unit vh1 = get(get(a, orient_), HIGH); Unit vh2 = get(get(b, orient_), HIGH); if(vh1 > vh2) return false; if(vh1 == vh2) { Unit hh1 = get(get(a, perp), HIGH); Unit hh2 = get(get(b, perp), HIGH); return hh1 < hh2; } } } return true; } }; template <typename T> template <typename interval_type_1> inline void rectangle_data<T>::set(orientation_2d orient, const interval_type_1& interval) { assign(ranges_[orient.to_int()], interval); } template <class T> template <class T2> rectangle_data<T>& rectangle_data<T>::operator=(const T2& rvalue) { assign(*this, rvalue); return *this; } template <class T> template <class T2> bool rectangle_data<T>::operator==(const T2& rvalue) const { return equivalence(*this, rvalue); } template <typename T> struct geometry_concept<rectangle_data<T> > { typedef rectangle_concept type; }; } } #endif polygon_set_concept.hpp 0000644 00000063712 15125572616 0011355 0 ustar 00 /* 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_SET_CONCEPT_HPP #define BOOST_POLYGON_POLYGON_SET_CONCEPT_HPP #include "polygon_set_data.hpp" #include "detail/polygon_simplify.hpp" namespace boost { namespace polygon{ template <typename T, typename T2> struct is_either_polygon_set_type { typedef typename gtl_or<typename is_polygon_set_type<T>::type, typename is_polygon_set_type<T2>::type >::type type; }; template <typename T> struct is_any_polygon_set_type { typedef typename gtl_or<typename is_polygon_45_or_90_set_type<T>::type, typename is_polygon_set_type<T>::type >::type type; }; template <typename polygon_set_type> typename enable_if< typename is_any_polygon_set_type<polygon_set_type>::type, typename polygon_set_traits<polygon_set_type>::iterator_type>::type begin_polygon_set_data(const polygon_set_type& polygon_set) { return polygon_set_traits<polygon_set_type>::begin(polygon_set); } template <typename polygon_set_type> typename enable_if< typename is_any_polygon_set_type<polygon_set_type>::type, typename polygon_set_traits<polygon_set_type>::iterator_type>::type end_polygon_set_data(const polygon_set_type& polygon_set) { return polygon_set_traits<polygon_set_type>::end(polygon_set); } template <typename polygon_set_type> typename enable_if< typename is_polygon_set_type<polygon_set_type>::type, bool>::type clean(const polygon_set_type& polygon_set) { return polygon_set_traits<polygon_set_type>::clean(polygon_set); } //assign template <typename polygon_set_type_1, typename polygon_set_type_2> typename enable_if< typename gtl_and< typename is_mutable_polygon_set_type<polygon_set_type_1>::type, typename is_any_polygon_set_type<polygon_set_type_2>::type>::type, polygon_set_type_1>::type & assign(polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { if(clean(rvalue)) polygon_set_mutable_traits<polygon_set_type_1>::set(lvalue, begin_polygon_set_data(rvalue), end_polygon_set_data(rvalue)); else { polygon_set_data<typename polygon_set_traits<polygon_set_type_2>::coordinate_type> ps; ps.insert(begin_polygon_set_data(rvalue), end_polygon_set_data(rvalue)); ps.clean(); polygon_set_mutable_traits<polygon_set_type_1>::set(lvalue, ps.begin(), ps.end()); } return lvalue; } //get trapezoids template <typename output_container_type, typename polygon_set_type> typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, void>::type get_trapezoids(output_container_type& output, const polygon_set_type& polygon_set) { polygon_set_data<typename polygon_set_traits<polygon_set_type>::coordinate_type> ps; assign(ps, polygon_set); ps.get_trapezoids(output); } //get trapezoids template <typename output_container_type, typename polygon_set_type> typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, void>::type get_trapezoids(output_container_type& output, const polygon_set_type& polygon_set, orientation_2d orient) { polygon_set_data<typename polygon_set_traits<polygon_set_type>::coordinate_type> ps; assign(ps, polygon_set); ps.get_trapezoids(output, orient); } //equivalence template <typename polygon_set_type_1, typename polygon_set_type_2> typename enable_if< typename gtl_and_3 < typename is_any_polygon_set_type<polygon_set_type_1>::type, typename is_any_polygon_set_type<polygon_set_type_2>::type, typename is_either_polygon_set_type<polygon_set_type_1, polygon_set_type_2>::type>::type, bool>::type equivalence(const polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { polygon_set_data<typename polygon_set_traits<polygon_set_type_1>::coordinate_type> ps1; assign(ps1, lvalue); polygon_set_data<typename polygon_set_traits<polygon_set_type_2>::coordinate_type> ps2; assign(ps2, rvalue); return ps1 == ps2; } //clear template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, void>::type clear(polygon_set_type& polygon_set) { polygon_set_data<typename polygon_set_traits<polygon_set_type>::coordinate_type> ps; assign(polygon_set, ps); } //empty template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, bool>::type empty(const polygon_set_type& polygon_set) { if(clean(polygon_set)) return begin_polygon_set_data(polygon_set) == end_polygon_set_data(polygon_set); polygon_set_data<typename polygon_set_traits<polygon_set_type>::coordinate_type> ps; assign(ps, polygon_set); ps.clean(); return ps.empty(); } //extents template <typename polygon_set_type, typename rectangle_type> typename enable_if< typename gtl_and< typename is_mutable_polygon_set_type<polygon_set_type>::type, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, bool>::type extents(rectangle_type& extents_rectangle, const polygon_set_type& polygon_set) { clean(polygon_set); polygon_set_data<typename polygon_set_traits<polygon_set_type>::coordinate_type> ps; assign(ps, polygon_set); return ps.extents(extents_rectangle); } //area template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::area_type>::type area(const polygon_set_type& polygon_set) { typedef typename polygon_set_traits<polygon_set_type>::coordinate_type Unit; typedef polygon_with_holes_data<Unit> p_type; typedef typename coordinate_traits<Unit>::area_type area_type; std::vector<p_type> polys; assign(polys, polygon_set); area_type retval = (area_type)0; for(std::size_t i = 0; i < polys.size(); ++i) { retval += area(polys[i]); } return retval; } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, std::size_t>::type simplify(polygon_set_type& polygon_set, typename coordinate_traits< typename polygon_set_traits<polygon_set_type>::coordinate_type >::coordinate_distance threshold) { typedef typename polygon_set_traits<polygon_set_type>::coordinate_type Unit; typedef polygon_with_holes_data<Unit> p_type; std::vector<p_type> polys; assign(polys, polygon_set); std::size_t retval = 0; for(std::size_t i = 0; i < polys.size(); ++i) { retval += detail::simplify_detail::simplify(polys[i].self_.coords_, polys[i].self_.coords_, threshold); for(typename std::list<polygon_data<Unit> >::iterator itrh = polys[i].holes_.begin(); itrh != (polys[i].holes_.end()); ++itrh) { retval += detail::simplify_detail::simplify((*itrh).coords_, (*itrh).coords_, threshold); } } assign(polygon_set, polys); return retval; } template <typename polygon_set_type, typename coord_type> typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, polygon_set_type>::type & resize(polygon_set_type& polygon_set, coord_type resizing, bool corner_fill_arcs = false, int num_circle_segments = 0) { typedef typename polygon_set_traits<polygon_set_type>::coordinate_type Unit; clean(polygon_set); polygon_set_data<Unit> ps; assign(ps, polygon_set); ps.resize(resizing, corner_fill_arcs,num_circle_segments); assign(polygon_set, ps); return polygon_set; } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, polygon_set_type>::type & bloat(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { return resize(polygon_set, bloating); } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, polygon_set_type>::type & shrink(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type shrinking) { return resize(polygon_set, -(typename polygon_set_traits<polygon_set_type>::coordinate_type)shrinking); } //interact template <typename polygon_set_type_1, typename polygon_set_type_2> typename enable_if< typename gtl_and_3 < typename is_any_polygon_set_type<polygon_set_type_1>::type, typename is_any_polygon_set_type<polygon_set_type_2>::type, typename is_either_polygon_set_type<polygon_set_type_1, polygon_set_type_2>::type>::type, polygon_set_type_1>::type& interact(polygon_set_type_1& polygon_set_1, const polygon_set_type_2& polygon_set_2) { polygon_set_data<typename polygon_set_traits<polygon_set_type_1>::coordinate_type> ps1; assign(ps1, polygon_set_1); polygon_set_data<typename polygon_set_traits<polygon_set_type_2>::coordinate_type> ps2; assign(ps2, polygon_set_2); ps1.interact(ps2); assign(polygon_set_1, ps1); return polygon_set_1; } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, polygon_set_type>::type & scale_up(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type factor) { typedef typename polygon_set_traits<polygon_set_type>::coordinate_type Unit; clean(polygon_set); polygon_set_data<Unit> ps; assign(ps, polygon_set); ps.scale_up(factor); assign(polygon_set, ps); return polygon_set; } template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, polygon_set_type>::type & scale_down(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type factor) { typedef typename polygon_set_traits<polygon_set_type>::coordinate_type Unit; clean(polygon_set); polygon_set_data<Unit> ps; assign(ps, polygon_set); ps.scale_down(factor); assign(polygon_set, ps); return polygon_set; } //transform template <typename polygon_set_type, typename transformation_type> typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, polygon_set_type>::type & transform(polygon_set_type& polygon_set, const transformation_type& transformation) { typedef typename polygon_set_traits<polygon_set_type>::coordinate_type Unit; clean(polygon_set); polygon_set_data<Unit> ps; assign(ps, polygon_set); ps.transform(transformation); assign(polygon_set, ps); return polygon_set; } //keep template <typename polygon_set_type> typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, polygon_set_type>::type & keep(polygon_set_type& polygon_set, typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::area_type min_area, typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::area_type max_area, typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type min_width, typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type max_width, typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type min_height, typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type max_height) { typedef typename polygon_set_traits<polygon_set_type>::coordinate_type Unit; typedef typename coordinate_traits<Unit>::unsigned_area_type uat; std::list<polygon_with_holes_data<Unit> > polys; assign(polys, polygon_set); typename std::list<polygon_with_holes_data<Unit> >::iterator itr_nxt; for(typename std::list<polygon_with_holes_data<Unit> >::iterator itr = polys.begin(); itr != polys.end(); itr = itr_nxt){ itr_nxt = itr; ++itr_nxt; rectangle_data<Unit> bbox; extents(bbox, *itr); uat pwidth = delta(bbox, HORIZONTAL); if(pwidth > min_width && pwidth <= max_width){ uat pheight = delta(bbox, VERTICAL); if(pheight > min_height && pheight <= max_height){ typename coordinate_traits<Unit>::area_type parea = area(*itr); if(parea <= max_area && parea >= min_area) { continue; } } } polys.erase(itr); } assign(polygon_set, polys); return polygon_set; } namespace operators { struct yes_ps_ob : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_4 < yes_ps_ob, typename is_any_polygon_set_type<geometry_type_1>::type, typename is_any_polygon_set_type<geometry_type_2>::type, typename is_either_polygon_set_type<geometry_type_1, geometry_type_2>::type>::type, polygon_set_view<geometry_type_1, geometry_type_2, 0> >::type operator|(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_set_view<geometry_type_1, geometry_type_2, 0> (lvalue, rvalue); } struct yes_ps_op : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_4 < yes_ps_op, typename gtl_if<typename is_any_polygon_set_type<geometry_type_1>::type>::type, typename gtl_if<typename is_any_polygon_set_type<geometry_type_2>::type>::type, typename gtl_if<typename is_either_polygon_set_type<geometry_type_1, geometry_type_2>::type>::type> ::type, polygon_set_view<geometry_type_1, geometry_type_2, 0> >::type operator+(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_set_view<geometry_type_1, geometry_type_2, 0> (lvalue, rvalue); } struct yes_ps_os : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_4 < yes_ps_os, typename is_any_polygon_set_type<geometry_type_1>::type, typename is_any_polygon_set_type<geometry_type_2>::type, typename is_either_polygon_set_type<geometry_type_1, geometry_type_2>::type>::type, polygon_set_view<geometry_type_1, geometry_type_2, 1> >::type operator*(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_set_view<geometry_type_1, geometry_type_2, 1> (lvalue, rvalue); } struct yes_ps_oa : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_4 < yes_ps_oa, typename is_any_polygon_set_type<geometry_type_1>::type, typename is_any_polygon_set_type<geometry_type_2>::type, typename is_either_polygon_set_type<geometry_type_1, geometry_type_2>::type>::type, polygon_set_view<geometry_type_1, geometry_type_2, 1> >::type operator&(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_set_view<geometry_type_1, geometry_type_2, 1> (lvalue, rvalue); } struct yes_ps_ox : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_4 < yes_ps_ox, typename is_any_polygon_set_type<geometry_type_1>::type, typename is_any_polygon_set_type<geometry_type_2>::type, typename is_either_polygon_set_type<geometry_type_1, geometry_type_2>::type>::type, polygon_set_view<geometry_type_1, geometry_type_2, 2> >::type operator^(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_set_view<geometry_type_1, geometry_type_2, 2> (lvalue, rvalue); } struct yes_ps_om : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_4 < yes_ps_om, typename gtl_if<typename is_any_polygon_set_type<geometry_type_1>::type>::type, typename gtl_if<typename is_any_polygon_set_type<geometry_type_2>::type>::type, typename gtl_if<typename is_either_polygon_set_type<geometry_type_1, geometry_type_2>::type>::type> ::type, polygon_set_view<geometry_type_1, geometry_type_2, 3> >::type operator-(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_set_view<geometry_type_1, geometry_type_2, 3> (lvalue, rvalue); } struct yes_ps_ope : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_4< yes_ps_ope, gtl_yes, typename is_mutable_polygon_set_type<geometry_type_1>::type, typename is_any_polygon_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator+=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op<geometry_type_1, geometry_type_2, 0>(lvalue, rvalue); } struct yes_ps_obe : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3< yes_ps_obe, typename is_mutable_polygon_set_type<geometry_type_1>::type, typename is_any_polygon_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator|=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op<geometry_type_1, geometry_type_2, 0>(lvalue, rvalue); } struct yes_ps_ose : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3< yes_ps_ose, typename is_mutable_polygon_set_type<geometry_type_1>::type, typename is_any_polygon_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator*=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op<geometry_type_1, geometry_type_2, 1>(lvalue, rvalue); } struct yes_ps_oae : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3< yes_ps_oae, typename is_mutable_polygon_set_type<geometry_type_1>::type, typename is_any_polygon_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator&=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op<geometry_type_1, geometry_type_2, 1>(lvalue, rvalue); } struct yes_ps_oxe : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3< yes_ps_oxe, typename is_mutable_polygon_set_type<geometry_type_1>::type, typename is_any_polygon_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator^=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op<geometry_type_1, geometry_type_2, 2>(lvalue, rvalue); } struct yes_ps_ome : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3< yes_ps_ome, typename is_mutable_polygon_set_type<geometry_type_1>::type, typename is_any_polygon_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator-=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op<geometry_type_1, geometry_type_2, 3>(lvalue, rvalue); } // TODO: Dafna, test these four resizing operators struct y_ps_rpe : gtl_yes {}; template <typename geometry_type_1, typename coordinate_type_1> typename enable_if< typename gtl_and_3< y_ps_rpe, typename is_mutable_polygon_set_type<geometry_type_1>::type, typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type>::type, geometry_type_1>::type & operator+=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { return resize(lvalue, rvalue); } struct y_ps_rme : gtl_yes {}; template <typename geometry_type_1, typename coordinate_type_1> typename enable_if< typename gtl_and_3<y_ps_rme, typename gtl_if<typename is_mutable_polygon_set_type<geometry_type_1>::type>::type, typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type>::type, geometry_type_1>::type & operator-=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { return resize(lvalue, -rvalue); } struct y_ps_rp : gtl_yes {}; template <typename geometry_type_1, typename coordinate_type_1> typename enable_if< typename gtl_and_3<y_ps_rp, typename gtl_if<typename is_mutable_polygon_set_type<geometry_type_1>::type>::type, typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type> ::type, geometry_type_1>::type operator+(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { geometry_type_1 retval(lvalue); retval += rvalue; return retval; } struct y_ps_rm : gtl_yes {}; template <typename geometry_type_1, typename coordinate_type_1> typename enable_if< typename gtl_and_3<y_ps_rm, typename gtl_if<typename is_mutable_polygon_set_type<geometry_type_1>::type>::type, typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type> ::type, geometry_type_1>::type operator-(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { geometry_type_1 retval(lvalue); retval -= rvalue; return retval; } } //end operators namespace template <typename T> struct view_of<polygon_45_set_concept, T> { typedef typename get_coordinate_type<T, typename geometry_concept<T>::type >::type coordinate_type; T* tp; std::vector<polygon_45_with_holes_data<coordinate_type> > polys; view_of(const T& obj) : tp(), polys() { std::vector<polygon_with_holes_data<coordinate_type> > gpolys; assign(gpolys, obj); for(typename std::vector<polygon_with_holes_data<coordinate_type> >::iterator itr = gpolys.begin(); itr != gpolys.end(); ++itr) { polys.push_back(polygon_45_with_holes_data<coordinate_type>()); assign(polys.back(), view_as<polygon_45_with_holes_concept>(*itr)); } } view_of(T& obj) : tp(&obj), polys() { std::vector<polygon_with_holes_data<coordinate_type> > gpolys; assign(gpolys, obj); for(typename std::vector<polygon_with_holes_data<coordinate_type> >::iterator itr = gpolys.begin(); itr != gpolys.end(); ++itr) { polys.push_back(polygon_45_with_holes_data<coordinate_type>()); assign(polys.back(), view_as<polygon_45_with_holes_concept>(*itr)); } } typedef typename std::vector<polygon_45_with_holes_data<coordinate_type> >::const_iterator iterator_type; typedef view_of operator_arg_type; inline iterator_type begin() const { return polys.begin(); } inline iterator_type end() const { return polys.end(); } inline orientation_2d orient() const { return HORIZONTAL; } inline bool clean() const { return false; } inline bool sorted() const { return false; } inline T& get() { return *tp; } }; template <typename T> struct polygon_45_set_traits<view_of<polygon_45_set_concept, T> > { typedef typename view_of<polygon_45_set_concept, T>::coordinate_type coordinate_type; typedef typename view_of<polygon_45_set_concept, T>::iterator_type iterator_type; typedef view_of<polygon_45_set_concept, T> operator_arg_type; static inline iterator_type begin(const view_of<polygon_45_set_concept, T>& polygon_set) { return polygon_set.begin(); } static inline iterator_type end(const view_of<polygon_45_set_concept, T>& polygon_set) { return polygon_set.end(); } static inline orientation_2d orient(const view_of<polygon_45_set_concept, T>& polygon_set) { return polygon_set.orient(); } static inline bool clean(const view_of<polygon_45_set_concept, T>& polygon_set) { return polygon_set.clean(); } static inline bool sorted(const view_of<polygon_45_set_concept, T>& polygon_set) { return polygon_set.sorted(); } }; template <typename T> struct geometry_concept<view_of<polygon_45_set_concept, T> > { typedef polygon_45_set_concept type; }; template <typename T> struct get_coordinate_type<view_of<polygon_45_set_concept, T>, polygon_45_set_concept> { typedef typename view_of<polygon_45_set_concept, T>::coordinate_type type; }; template <typename T> struct get_iterator_type_2<view_of<polygon_45_set_concept, T>, polygon_45_set_concept> { typedef typename view_of<polygon_45_set_concept, T>::iterator_type type; static type begin(const view_of<polygon_45_set_concept, T>& t) { return t.begin(); } static type end(const view_of<polygon_45_set_concept, T>& t) { return t.end(); } }; } } #endif polygon_with_holes_data.hpp 0000644 00000006602 15125572616 0012200 0 ustar 00 /* 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_WITH_HOLES_DATA_HPP #define BOOST_POLYGON_POLYGON_WITH_HOLES_DATA_HPP #include "isotropy.hpp" #include "polygon_data.hpp" namespace boost { namespace polygon{ struct polygon_with_holes_concept; template <typename T> class polygon_with_holes_data { public: typedef polygon_with_holes_concept geometry_type; typedef T coordinate_type; typedef typename polygon_data<T>::iterator_type iterator_type; typedef typename std::list<polygon_data<coordinate_type> >::const_iterator iterator_holes_type; typedef polygon_data<coordinate_type> hole_type; typedef typename coordinate_traits<T>::coordinate_distance area_type; typedef point_data<T> point_type; // default constructor of point does not initialize x and y inline polygon_with_holes_data() : self_(), holes_() {} //do nothing default constructor template<class iT> inline polygon_with_holes_data(iT input_begin, iT input_end) : self_(), holes_() { set(input_begin, input_end); } template<class iT, typename hiT> inline polygon_with_holes_data(iT input_begin, iT input_end, hiT holes_begin, hiT holes_end) : self_(), holes_() { set(input_begin, input_end); set_holes(holes_begin, holes_end); } template<class iT> inline polygon_with_holes_data& set(iT input_begin, iT input_end) { self_.set(input_begin, input_end); return *this; } // initialize a polygon from x,y values, it is assumed that the first is an x // and that the input is a well behaved polygon template<class iT> inline polygon_with_holes_data& set_holes(iT input_begin, iT input_end) { holes_.clear(); //just in case there was some old data there for( ; input_begin != input_end; ++ input_begin) { holes_.push_back(hole_type()); holes_.back().set((*input_begin).begin(), (*input_begin).end()); } return *this; } // copy constructor (since we have dynamic memory) inline polygon_with_holes_data(const polygon_with_holes_data& that) : self_(that.self_), holes_(that.holes_) {} // assignment operator (since we have dynamic memory do a deep copy) inline polygon_with_holes_data& operator=(const polygon_with_holes_data& that) { self_ = that.self_; holes_ = that.holes_; return *this; } template <typename T2> inline polygon_with_holes_data& operator=(const T2& rvalue); // get begin iterator, returns a pointer to a const coordinate_type inline const iterator_type begin() const { return self_.begin(); } // get end iterator, returns a pointer to a const coordinate_type inline const iterator_type end() const { return self_.end(); } inline std::size_t size() const { return self_.size(); } // get begin iterator, returns a pointer to a const polygon inline const iterator_holes_type begin_holes() const { return holes_.begin(); } // get end iterator, returns a pointer to a const polygon inline const iterator_holes_type end_holes() const { return holes_.end(); } inline std::size_t size_holes() const { return holes_.size(); } public: polygon_data<coordinate_type> self_; std::list<hole_type> holes_; }; } } #endif polygon_traits.hpp 0000644 00000220704 15125572616 0010351 0 ustar 00 /* 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_TRAITS_HPP #define BOOST_POLYGON_POLYGON_TRAITS_HPP namespace boost { namespace polygon{ template <typename T, typename enable = gtl_yes> struct polygon_90_traits { typedef typename T::coordinate_type coordinate_type; typedef typename T::compact_iterator_type compact_iterator_type; // Get the begin iterator static inline compact_iterator_type begin_compact(const T& t) { return t.begin_compact(); } // Get the end iterator static inline compact_iterator_type end_compact(const T& t) { return t.end_compact(); } // Get the number of sides of the polygon static inline std::size_t size(const T& t) { return t.size(); } // Get the winding direction of the polygon static inline winding_direction winding(const T&) { return unknown_winding; } }; template <typename T> struct polygon_traits_general { typedef typename T::coordinate_type coordinate_type; typedef typename T::iterator_type iterator_type; typedef typename T::point_type point_type; // Get the begin iterator static inline iterator_type begin_points(const T& t) { return t.begin(); } // Get the end iterator static inline iterator_type end_points(const T& t) { return t.end(); } // Get the number of sides of the polygon static inline std::size_t size(const T& t) { return t.size(); } // Get the winding direction of the polygon static inline winding_direction winding(const T&) { return unknown_winding; } }; template <typename T> struct polygon_traits_90 { typedef typename polygon_90_traits<T>::coordinate_type coordinate_type; typedef iterator_compact_to_points<typename polygon_90_traits<T>::compact_iterator_type, point_data<coordinate_type> > iterator_type; typedef point_data<coordinate_type> point_type; // Get the begin iterator static inline iterator_type begin_points(const T& t) { return iterator_type(polygon_90_traits<T>::begin_compact(t), polygon_90_traits<T>::end_compact(t)); } // Get the end iterator static inline iterator_type end_points(const T& t) { return iterator_type(polygon_90_traits<T>::end_compact(t), polygon_90_traits<T>::end_compact(t)); } // Get the number of sides of the polygon static inline std::size_t size(const T& t) { return polygon_90_traits<T>::size(t); } // Get the winding direction of the polygon static inline winding_direction winding(const T& t) { return polygon_90_traits<T>::winding(t); } }; #ifndef BOOST_VERY_LITTLE_SFINAE template <typename T, typename enable = gtl_yes> struct polygon_traits {}; template <typename T> struct polygon_traits<T, typename gtl_or_4< typename gtl_same_type<typename geometry_concept<T>::type, polygon_concept>::type, typename gtl_same_type<typename geometry_concept<T>::type, polygon_45_concept>::type, typename gtl_same_type<typename geometry_concept<T>::type, polygon_with_holes_concept>::type, typename gtl_same_type<typename geometry_concept<T>::type, polygon_45_with_holes_concept>::type >::type> : public polygon_traits_general<T> {}; template <typename T> struct polygon_traits< T, typename gtl_or< typename gtl_same_type<typename geometry_concept<T>::type, polygon_90_concept>::type, typename gtl_same_type<typename geometry_concept<T>::type, polygon_90_with_holes_concept>::type >::type > : public polygon_traits_90<T> {}; #else template <typename T, typename T_IF, typename T_ELSE> struct gtl_ifelse {}; template <typename T_IF, typename T_ELSE> struct gtl_ifelse<gtl_no, T_IF, T_ELSE> { typedef T_ELSE type; }; template <typename T_IF, typename T_ELSE> struct gtl_ifelse<gtl_yes, T_IF, T_ELSE> { typedef T_IF type; }; template <typename T, typename enable = gtl_yes> struct polygon_traits {}; template <typename T> struct polygon_traits<T, typename gtl_or<typename gtl_or_4< typename gtl_same_type<typename geometry_concept<T>::type, polygon_concept>::type, typename gtl_same_type<typename geometry_concept<T>::type, polygon_45_concept>::type, typename gtl_same_type<typename geometry_concept<T>::type, polygon_with_holes_concept>::type, typename gtl_same_type<typename geometry_concept<T>::type, polygon_45_with_holes_concept>::type >::type, typename gtl_or< typename gtl_same_type<typename geometry_concept<T>::type, polygon_90_concept>::type, typename gtl_same_type<typename geometry_concept<T>::type, polygon_90_with_holes_concept>::type >::type>::type > : public gtl_ifelse<typename gtl_or< typename gtl_same_type<typename geometry_concept<T>::type, polygon_90_concept>::type, typename gtl_same_type<typename geometry_concept<T>::type, polygon_90_with_holes_concept>::type >::type, polygon_traits_90<T>, polygon_traits_general<T> >::type { }; #endif template <typename T, typename enable = void> struct polygon_with_holes_traits { typedef typename T::iterator_holes_type iterator_holes_type; typedef typename T::hole_type hole_type; // Get the begin iterator static inline iterator_holes_type begin_holes(const T& t) { return t.begin_holes(); } // Get the end iterator static inline iterator_holes_type end_holes(const T& t) { return t.end_holes(); } // Get the number of holes static inline std::size_t size_holes(const T& t) { return t.size_holes(); } }; template <typename T, typename enable = void> struct polygon_90_mutable_traits { // Set the data of a polygon with the unique coordinates in an iterator, starting with an x template <typename iT> static inline T& set_compact(T& t, iT input_begin, iT input_end) { t.set_compact(input_begin, input_end); return t; } }; template <typename T, typename enable = void> struct polygon_mutable_traits { // Set the data of a polygon with the unique coordinates in an iterator, starting with an x template <typename iT> static inline T& set_points(T& t, iT input_begin, iT input_end) { t.set(input_begin, input_end); return t; } }; template <typename T, typename enable = void> struct polygon_with_holes_mutable_traits { // Set the data of a polygon with the unique coordinates in an iterator, starting with an x template <typename iT> static inline T& set_holes(T& t, iT inputBegin, iT inputEnd) { t.set_holes(inputBegin, inputEnd); return t; } }; } } #include "isotropy.hpp" //point #include "point_data.hpp" #include "point_traits.hpp" #include "point_concept.hpp" //interval #include "interval_data.hpp" #include "interval_traits.hpp" #include "interval_concept.hpp" //rectangle #include "rectangle_data.hpp" #include "rectangle_traits.hpp" #include "rectangle_concept.hpp" //algorithms needed by polygon types #include "detail/iterator_points_to_compact.hpp" #include "detail/iterator_compact_to_points.hpp" //polygons #include "polygon_45_data.hpp" #include "polygon_data.hpp" #include "polygon_90_data.hpp" #include "polygon_90_with_holes_data.hpp" #include "polygon_45_with_holes_data.hpp" #include "polygon_with_holes_data.hpp" namespace boost { namespace polygon{ struct polygon_concept {}; struct polygon_with_holes_concept {}; struct polygon_45_concept {}; struct polygon_45_with_holes_concept {}; struct polygon_90_concept {}; struct polygon_90_with_holes_concept {}; template <typename T> struct is_polygon_90_type { typedef typename geometry_concept<T>::type GC; typedef typename gtl_same_type<polygon_90_concept, GC>::type type; }; template <typename T> struct is_polygon_45_type { typedef typename geometry_concept<T>::type GC; typedef typename gtl_or<typename is_polygon_90_type<T>::type, typename gtl_same_type<polygon_45_concept, GC>::type>::type type; }; template <typename T> struct is_polygon_type { typedef typename geometry_concept<T>::type GC; typedef typename gtl_or<typename is_polygon_45_type<T>::type, typename gtl_same_type<polygon_concept, GC>::type>::type type; }; template <typename T> struct is_polygon_90_with_holes_type { typedef typename geometry_concept<T>::type GC; typedef typename gtl_or<typename is_polygon_90_type<T>::type, typename gtl_same_type<polygon_90_with_holes_concept, GC>::type>::type type; }; template <typename T> struct is_polygon_45_with_holes_type { typedef typename geometry_concept<T>::type GC; typedef typename gtl_or_3<typename is_polygon_90_with_holes_type<T>::type, typename is_polygon_45_type<T>::type, typename gtl_same_type<polygon_45_with_holes_concept, GC>::type>::type type; }; template <typename T> struct is_polygon_with_holes_type { typedef typename geometry_concept<T>::type GC; typedef typename gtl_or_3<typename is_polygon_45_with_holes_type<T>::type, typename is_polygon_type<T>::type, typename gtl_same_type<polygon_with_holes_concept, GC>::type>::type type; }; template <typename T> struct is_mutable_polygon_90_type { typedef typename geometry_concept<T>::type GC; typedef typename gtl_same_type<polygon_90_concept, GC>::type type; }; template <typename T> struct is_mutable_polygon_45_type { typedef typename geometry_concept<T>::type GC; typedef typename gtl_same_type<polygon_45_concept, GC>::type type; }; template <typename T> struct is_mutable_polygon_type { typedef typename geometry_concept<T>::type GC; typedef typename gtl_same_type<polygon_concept, GC>::type type; }; template <typename T> struct is_mutable_polygon_90_with_holes_type { typedef typename geometry_concept<T>::type GC; typedef typename gtl_same_type<polygon_90_with_holes_concept, GC>::type type; }; template <typename T> struct is_mutable_polygon_45_with_holes_type { typedef typename geometry_concept<T>::type GC; typedef typename gtl_same_type<polygon_45_with_holes_concept, GC>::type type; }; template <typename T> struct is_mutable_polygon_with_holes_type { typedef typename geometry_concept<T>::type GC; typedef typename gtl_same_type<polygon_with_holes_concept, GC>::type type; }; template <typename T> struct is_any_mutable_polygon_with_holes_type { typedef typename gtl_or_3<typename is_mutable_polygon_90_with_holes_type<T>::type, typename is_mutable_polygon_45_with_holes_type<T>::type, typename is_mutable_polygon_with_holes_type<T>::type>::type type; }; template <typename T> struct is_any_mutable_polygon_without_holes_type { typedef typename gtl_or_3< typename is_mutable_polygon_90_type<T>::type, typename is_mutable_polygon_45_type<T>::type, typename is_mutable_polygon_type<T>::type>::type type; }; template <typename T> struct is_any_mutable_polygon_type { typedef typename gtl_or<typename is_any_mutable_polygon_with_holes_type<T>::type, typename is_any_mutable_polygon_without_holes_type<T>::type>::type type; }; template <typename T> struct polygon_from_polygon_with_holes_type {}; template <> struct polygon_from_polygon_with_holes_type<polygon_with_holes_concept> { typedef polygon_concept type; }; template <> struct polygon_from_polygon_with_holes_type<polygon_45_with_holes_concept> { typedef polygon_45_concept type; }; template <> struct polygon_from_polygon_with_holes_type<polygon_90_with_holes_concept> { typedef polygon_90_concept type; }; template <> struct geometry_domain<polygon_45_concept> { typedef forty_five_domain type; }; template <> struct geometry_domain<polygon_45_with_holes_concept> { typedef forty_five_domain type; }; template <> struct geometry_domain<polygon_90_concept> { typedef manhattan_domain type; }; template <> struct geometry_domain<polygon_90_with_holes_concept> { typedef manhattan_domain type; }; template <typename domain_type, typename coordinate_type> struct distance_type_by_domain { typedef typename coordinate_traits<coordinate_type>::coordinate_distance type; }; template <typename coordinate_type> struct distance_type_by_domain<manhattan_domain, coordinate_type> { typedef typename coordinate_traits<coordinate_type>::coordinate_difference type; }; // \brief Sets the boundary of the polygon to the points in the iterator range // \tparam T A type that models polygon_concept // \tparam iT Iterator type over objects that model point_concept // \param t The polygon to set // \param begin_points The start of the range of points // \param end_points The end of the range of points /// \relatesalso polygon_concept template <typename T, typename iT> typename enable_if <typename is_any_mutable_polygon_type<T>::type, T>::type & set_points(T& t, iT begin_points, iT end_points) { polygon_mutable_traits<T>::set_points(t, begin_points, end_points); return t; } // \brief Sets the boundary of the polygon to the non-redundant coordinates in the iterator range // \tparam T A type that models polygon_90_concept // \tparam iT Iterator type over objects that model coordinate_concept // \param t The polygon to set // \param begin_compact_coordinates The start of the range of coordinates // \param end_compact_coordinates The end of the range of coordinates /// \relatesalso polygon_90_concept template <typename T, typename iT> typename enable_if <typename gtl_or< typename is_mutable_polygon_90_type<T>::type, typename is_mutable_polygon_90_with_holes_type<T>::type>::type, T>::type & set_compact(T& t, iT begin_compact_coordinates, iT end_compact_coordinates) { polygon_90_mutable_traits<T>::set_compact(t, begin_compact_coordinates, end_compact_coordinates); return t; } /// \relatesalso polygon_with_holes_concept template <typename T, typename iT> typename enable_if< typename gtl_and < typename is_any_mutable_polygon_with_holes_type<T>::type, typename gtl_different_type<typename geometry_domain<typename geometry_concept<T>::type>::type, manhattan_domain>::type>::type, T>::type & set_compact(T& t, iT begin_compact_coordinates, iT end_compact_coordinates) { iterator_compact_to_points<iT, point_data<typename polygon_traits<T>::coordinate_type> > itrb(begin_compact_coordinates, end_compact_coordinates), itre(end_compact_coordinates, end_compact_coordinates); return set_points(t, itrb, itre); } /// \relatesalso polygon_with_holes_concept template <typename T, typename iT> typename enable_if <typename is_any_mutable_polygon_with_holes_type<T>::type, T>::type & set_holes(T& t, iT begin_holes, iT end_holes) { polygon_with_holes_mutable_traits<T>::set_holes(t, begin_holes, end_holes); return t; } /// \relatesalso polygon_90_concept template <typename T> typename polygon_90_traits<T>::compact_iterator_type begin_compact(const T& polygon, typename enable_if< typename gtl_and <typename is_polygon_with_holes_type<T>::type, typename gtl_same_type<typename geometry_domain<typename geometry_concept<T>::type>::type, manhattan_domain>::type>::type>::type * = 0 ) { return polygon_90_traits<T>::begin_compact(polygon); } /// \relatesalso polygon_90_concept template <typename T> typename polygon_90_traits<T>::compact_iterator_type end_compact(const T& polygon, typename enable_if< typename gtl_and <typename is_polygon_with_holes_type<T>::type, typename gtl_same_type<typename geometry_domain<typename geometry_concept<T>::type>::type, manhattan_domain>::type>::type>::type * = 0 ) { return polygon_90_traits<T>::end_compact(polygon); } /// \relatesalso polygon_concept template <typename T> typename enable_if < typename gtl_if< typename is_polygon_with_holes_type<T>::type>::type, typename polygon_traits<T>::iterator_type>::type begin_points(const T& polygon) { return polygon_traits<T>::begin_points(polygon); } /// \relatesalso polygon_concept template <typename T> typename enable_if < typename gtl_if< typename is_polygon_with_holes_type<T>::type>::type, typename polygon_traits<T>::iterator_type>::type end_points(const T& polygon) { return polygon_traits<T>::end_points(polygon); } /// \relatesalso polygon_concept template <typename T> typename enable_if <typename is_polygon_with_holes_type<T>::type, std::size_t>::type size(const T& polygon) { return polygon_traits<T>::size(polygon); } /// \relatesalso polygon_with_holes_concept template <typename T> typename enable_if < typename gtl_if< typename is_polygon_with_holes_type<T>::type>::type, typename polygon_with_holes_traits<T>::iterator_holes_type>::type begin_holes(const T& polygon) { return polygon_with_holes_traits<T>::begin_holes(polygon); } /// \relatesalso polygon_with_holes_concept template <typename T> typename enable_if < typename gtl_if< typename is_polygon_with_holes_type<T>::type>::type, typename polygon_with_holes_traits<T>::iterator_holes_type>::type end_holes(const T& polygon) { return polygon_with_holes_traits<T>::end_holes(polygon); } /// \relatesalso polygon_with_holes_concept template <typename T> typename enable_if <typename is_polygon_with_holes_type<T>::type, std::size_t>::type size_holes(const T& polygon) { return polygon_with_holes_traits<T>::size_holes(polygon); } // \relatesalso polygon_concept template <typename T1, typename T2> typename enable_if< typename gtl_and< typename is_mutable_polygon_type<T1>::type, typename is_polygon_type<T2>::type>::type, T1>::type & assign(T1& lvalue, const T2& rvalue) { polygon_mutable_traits<T1>::set_points(lvalue, polygon_traits<T2>::begin_points(rvalue), polygon_traits<T2>::end_points(rvalue)); return lvalue; } // \relatesalso polygon_with_holes_concept template <typename T1, typename T2> typename enable_if< typename gtl_and< typename is_mutable_polygon_with_holes_type<T1>::type, typename is_polygon_with_holes_type<T2>::type>::type, T1>::type & assign(T1& lvalue, const T2& rvalue) { polygon_mutable_traits<T1>::set_points(lvalue, polygon_traits<T2>::begin_points(rvalue), polygon_traits<T2>::end_points(rvalue)); polygon_with_holes_mutable_traits<T1>::set_holes(lvalue, polygon_with_holes_traits<T2>::begin_holes(rvalue), polygon_with_holes_traits<T2>::end_holes(rvalue)); return lvalue; } // \relatesalso polygon_45_concept template <typename T1, typename T2> typename enable_if< typename gtl_and< typename is_mutable_polygon_45_type<T1>::type, typename is_polygon_45_type<T2>::type>::type, T1>::type & assign(T1& lvalue, const T2& rvalue) { polygon_mutable_traits<T1>::set_points(lvalue, polygon_traits<T2>::begin_points(rvalue), polygon_traits<T2>::end_points(rvalue)); return lvalue; } // \relatesalso polygon_45_with_holes_concept template <typename T1, typename T2> typename enable_if< typename gtl_and< typename is_mutable_polygon_45_with_holes_type<T1>::type, typename is_polygon_45_with_holes_type<T2>::type>::type, T1>::type & assign(T1& lvalue, const T2& rvalue) { polygon_mutable_traits<T1>::set_points(lvalue, polygon_traits<T2>::begin_points(rvalue), polygon_traits<T2>::end_points(rvalue)); polygon_with_holes_mutable_traits<T1>::set_holes(lvalue, polygon_with_holes_traits<T2>::begin_holes(rvalue), polygon_with_holes_traits<T2>::end_holes(rvalue)); return lvalue; } // \relatesalso polygon_90_concept template <typename T1, typename T2> typename enable_if< typename gtl_and< typename is_mutable_polygon_90_type<T1>::type, typename is_polygon_90_type<T2>::type>::type, T1>::type & assign(T1& lvalue, const T2& rvalue) { polygon_90_mutable_traits<T1>::set_compact(lvalue, polygon_90_traits<T2>::begin_compact(rvalue), polygon_90_traits<T2>::end_compact(rvalue)); return lvalue; } // \relatesalso polygon_90_with_holes_concept template <typename T1, typename T2> typename enable_if< typename gtl_and< typename is_mutable_polygon_90_with_holes_type<T1>::type, typename is_polygon_90_with_holes_type<T2>::type>::type, T1>::type & assign(T1& lvalue, const T2& rvalue) { polygon_90_mutable_traits<T1>::set_compact(lvalue, polygon_90_traits<T2>::begin_compact(rvalue), polygon_90_traits<T2>::end_compact(rvalue)); polygon_with_holes_mutable_traits<T1>::set_holes(lvalue, polygon_with_holes_traits<T2>::begin_holes(rvalue), polygon_with_holes_traits<T2>::end_holes(rvalue)); return lvalue; } // \relatesalso polygon_90_concept template <typename T1, typename T2> typename enable_if< typename gtl_and< typename is_any_mutable_polygon_type<T1>::type, typename is_rectangle_concept<typename geometry_concept<T2>::type>::type>::type, T1>::type & assign(T1& polygon, const T2& rect) { typedef point_data<typename polygon_traits<T1>::coordinate_type> PT; PT points[4] = {PT(xl(rect), yl(rect)), PT(xh(rect), yl(rect)), PT(xh(rect), yh(rect)), PT(xl(rect), yh(rect))}; set_points(polygon, points, points+4); return polygon; } /// \relatesalso polygon_90_concept template <typename polygon_type, typename point_type> typename enable_if< typename gtl_and< typename is_mutable_polygon_90_type<polygon_type>::type, typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, polygon_type>::type & convolve(polygon_type& polygon, const point_type& point) { std::vector<typename polygon_90_traits<polygon_type>::coordinate_type> coords; coords.reserve(::boost::polygon::size(polygon)); bool pingpong = true; for(typename polygon_90_traits<polygon_type>::compact_iterator_type iter = begin_compact(polygon); iter != end_compact(polygon); ++iter) { coords.push_back((*iter) + (pingpong ? x(point) : y(point))); pingpong = !pingpong; } polygon_90_mutable_traits<polygon_type>::set_compact(polygon, coords.begin(), coords.end()); return polygon; } /// \relatesalso polygon_concept template <typename polygon_type, typename point_type> typename enable_if< typename gtl_and< typename gtl_or< typename is_mutable_polygon_45_type<polygon_type>::type, typename is_mutable_polygon_type<polygon_type>::type>::type, typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, polygon_type>::type & convolve(polygon_type& polygon, const point_type& point) { std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; points.reserve(::boost::polygon::size(polygon)); for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); convolve(points.back(), point); } polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); return polygon; } /// \relatesalso polygon_with_holes_concept template <typename polygon_type, typename point_type> typename enable_if< typename gtl_and< typename is_any_mutable_polygon_with_holes_type<polygon_type>::type, typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, polygon_type>::type & convolve(polygon_type& polygon, const point_type& point) { typedef typename polygon_with_holes_traits<polygon_type>::hole_type hole_type; hole_type h; set_points(h, begin_points(polygon), end_points(polygon)); convolve(h, point); std::vector<hole_type> holes; holes.reserve(size_holes(polygon)); for(typename polygon_with_holes_traits<polygon_type>::iterator_holes_type itr = begin_holes(polygon); itr != end_holes(polygon); ++itr) { holes.push_back(*itr); convolve(holes.back(), point); } assign(polygon, h); set_holes(polygon, holes.begin(), holes.end()); return polygon; } /// \relatesalso polygon_concept template <typename T> typename enable_if< typename is_any_mutable_polygon_type<T>::type, T>::type & move(T& polygon, orientation_2d orient, typename polygon_traits<T>::coordinate_type displacement) { typedef typename polygon_traits<T>::coordinate_type Unit; if(orient == HORIZONTAL) return convolve(polygon, point_data<Unit>(displacement, Unit(0))); return convolve(polygon, point_data<Unit>(Unit(0), displacement)); } /// \relatesalso polygon_concept /// \brief Applies a transformation to the polygon. /// \tparam polygon_type A type that models polygon_concept /// \tparam transform_type A type that may be either axis_transformation or transformation or that overloads point_concept::transform /// \param polygon The polygon to transform /// \param tr The transformation to apply template <typename polygon_type, typename transform_type> typename enable_if< typename is_any_mutable_polygon_without_holes_type<polygon_type>::type, polygon_type>::type & transform(polygon_type& polygon, const transform_type& tr) { std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; points.reserve(::boost::polygon::size(polygon)); for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); transform(points.back(), tr); } polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); return polygon; } /// \relatesalso polygon_with_holes_concept template <typename T, typename transform_type> typename enable_if< typename is_any_mutable_polygon_with_holes_type<T>::type, T>::type & transform(T& polygon, const transform_type& tr) { typedef typename polygon_with_holes_traits<T>::hole_type hole_type; hole_type h; set_points(h, begin_points(polygon), end_points(polygon)); transform(h, tr); std::vector<hole_type> holes; holes.reserve(size_holes(polygon)); for(typename polygon_with_holes_traits<T>::iterator_holes_type itr = begin_holes(polygon); itr != end_holes(polygon); ++itr) { holes.push_back(*itr); transform(holes.back(), tr); } assign(polygon, h); set_holes(polygon, holes.begin(), holes.end()); return polygon; } template <typename polygon_type> typename enable_if< typename is_any_mutable_polygon_without_holes_type<polygon_type>::type, polygon_type>::type & scale_up(polygon_type& polygon, typename coordinate_traits<typename polygon_traits<polygon_type>::coordinate_type>::unsigned_area_type factor) { std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; points.reserve(::boost::polygon::size(polygon)); for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); scale_up(points.back(), factor); } polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); return polygon; } template <typename T> typename enable_if< typename is_any_mutable_polygon_with_holes_type<T>::type, T>::type & scale_up(T& polygon, typename coordinate_traits<typename polygon_traits<T>::coordinate_type>::unsigned_area_type factor) { typedef typename polygon_with_holes_traits<T>::hole_type hole_type; hole_type h; set_points(h, begin_points(polygon), end_points(polygon)); scale_up(h, factor); std::vector<hole_type> holes; holes.reserve(size_holes(polygon)); for(typename polygon_with_holes_traits<T>::iterator_holes_type itr = begin_holes(polygon); itr != end_holes(polygon); ++itr) { holes.push_back(*itr); scale_up(holes.back(), factor); } assign(polygon, h); set_holes(polygon, holes.begin(), holes.end()); return polygon; } //scale non-45 down template <typename polygon_type> typename enable_if< typename gtl_and< typename is_any_mutable_polygon_without_holes_type<polygon_type>::type, typename gtl_not<typename gtl_same_type < forty_five_domain, typename geometry_domain<typename geometry_concept<polygon_type>::type>::type>::type>::type>::type, polygon_type>::type & scale_down(polygon_type& polygon, typename coordinate_traits<typename polygon_traits<polygon_type>::coordinate_type>::unsigned_area_type factor) { std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; points.reserve(::boost::polygon::size(polygon)); for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); scale_down(points.back(), factor); } polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); return polygon; } template <typename Unit> Unit local_abs(Unit value) { return value < 0 ? (Unit)-value : value; } template <typename Unit> void snap_point_vector_to_45(std::vector<point_data<Unit> >& pts) { typedef point_data<Unit> Point; if(pts.size() < 3) { pts.clear(); return; } typename std::vector<point_data<Unit> >::iterator endLocation = std::unique(pts.begin(), pts.end()); if(endLocation != pts.end()){ pts.resize(endLocation - pts.begin()); } if(pts.back() == pts[0]) pts.pop_back(); //iterate over point triplets int numPts = pts.size(); bool wrap_around = false; for(int i = 0; i < numPts; ++i) { Point& pt1 = pts[i]; Point& pt2 = pts[(i + 1) % numPts]; Point& pt3 = pts[(i + 2) % numPts]; //check if non-45 edge Unit deltax = x(pt2) - x(pt1); Unit deltay = y(pt2) - y(pt1); if(deltax && deltay && local_abs(deltax) != local_abs(deltay)) { //adjust the middle point Unit ndx = x(pt3) - x(pt2); Unit ndy = y(pt3) - y(pt2); if(ndx && ndy) { Unit diff = local_abs(local_abs(deltax) - local_abs(deltay)); Unit halfdiff = diff/2; if((deltax > 0 && deltay > 0) || (deltax < 0 && deltay < 0)) { //previous edge is rising slope if(local_abs(deltax + halfdiff + (diff % 2)) == local_abs(deltay - halfdiff)) { x(pt2, x(pt2) + halfdiff + (diff % 2)); y(pt2, y(pt2) - halfdiff); } else if(local_abs(deltax - halfdiff - (diff % 2)) == local_abs(deltay + halfdiff)) { x(pt2, x(pt2) - halfdiff - (diff % 2)); y(pt2, y(pt2) + halfdiff); } else{ //std::cout << "fail1\n"; } } else { //previous edge is falling slope if(local_abs(deltax + halfdiff + (diff % 2)) == local_abs(deltay + halfdiff)) { x(pt2, x(pt2) + halfdiff + (diff % 2)); y(pt2, y(pt2) + halfdiff); } else if(local_abs(deltax - halfdiff - (diff % 2)) == local_abs(deltay - halfdiff)) { x(pt2, x(pt2) - halfdiff - (diff % 2)); y(pt2, y(pt2) - halfdiff); } else { //std::cout << "fail2\n"; } } if(i == numPts - 1 && (diff % 2)) { //we have a wrap around effect if(!wrap_around) { wrap_around = true; i = -1; } } } else if(ndx) { //next edge is horizontal //find the x value for pt1 that would make the abs(deltax) == abs(deltay) Unit newDeltaX = local_abs(deltay); if(deltax < 0) newDeltaX *= -1; x(pt2, x(pt1) + newDeltaX); } else { //ndy //next edge is vertical //find the y value for pt1 that would make the abs(deltax) == abs(deltay) Unit newDeltaY = local_abs(deltax); if(deltay < 0) newDeltaY *= -1; y(pt2, y(pt1) + newDeltaY); } } } } template <typename polygon_type> typename enable_if< typename is_any_mutable_polygon_without_holes_type<polygon_type>::type, polygon_type>::type & snap_to_45(polygon_type& polygon) { std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; points.reserve(::boost::polygon::size(polygon)); for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); } snap_point_vector_to_45(points); polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); return polygon; } template <typename polygon_type> typename enable_if< typename is_any_mutable_polygon_with_holes_type<polygon_type>::type, polygon_type>::type & snap_to_45(polygon_type& polygon) { typedef typename polygon_with_holes_traits<polygon_type>::hole_type hole_type; hole_type h; set_points(h, begin_points(polygon), end_points(polygon)); snap_to_45(h); std::vector<hole_type> holes; holes.reserve(size_holes(polygon)); for(typename polygon_with_holes_traits<polygon_type>::iterator_holes_type itr = begin_holes(polygon); itr != end_holes(polygon); ++itr) { holes.push_back(*itr); snap_to_45(holes.back()); } assign(polygon, h); set_holes(polygon, holes.begin(), holes.end()); return polygon; } //scale specifically 45 down template <typename polygon_type> typename enable_if< typename gtl_and< typename is_any_mutable_polygon_without_holes_type<polygon_type>::type, typename gtl_same_type < forty_five_domain, typename geometry_domain<typename geometry_concept<polygon_type>::type>::type>::type>::type, polygon_type>::type & scale_down(polygon_type& polygon, typename coordinate_traits<typename polygon_traits<polygon_type>::coordinate_type>::unsigned_area_type factor) { std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; points.reserve(::boost::polygon::size(polygon)); for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); scale_down(points.back(), factor); } snap_point_vector_to_45(points); polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); return polygon; } template <typename T> typename enable_if< typename is_any_mutable_polygon_with_holes_type<T>::type, T>::type & scale_down(T& polygon, typename coordinate_traits<typename polygon_traits<T>::coordinate_type>::unsigned_area_type factor) { typedef typename polygon_with_holes_traits<T>::hole_type hole_type; hole_type h; set_points(h, begin_points(polygon), end_points(polygon)); scale_down(h, factor); std::vector<hole_type> holes; holes.reserve(size_holes(polygon)); for(typename polygon_with_holes_traits<T>::iterator_holes_type itr = begin_holes(polygon); itr != end_holes(polygon); ++itr) { holes.push_back(*itr); scale_down(holes.back(), factor); } assign(polygon, h); set_holes(polygon, holes.begin(), holes.end()); return polygon; } //scale non-45 template <typename polygon_type> typename enable_if< typename gtl_and< typename is_any_mutable_polygon_without_holes_type<polygon_type>::type, typename gtl_not<typename gtl_same_type < forty_five_domain, typename geometry_domain<typename geometry_concept<polygon_type>::type>::type>::type>::type>::type, polygon_type>::type & scale(polygon_type& polygon, double factor) { std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; points.reserve(::boost::polygon::size(polygon)); for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); scale(points.back(), anisotropic_scale_factor<double>(factor, factor)); } polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); return polygon; } //scale specifically 45 template <typename polygon_type> polygon_type& scale(polygon_type& polygon, double factor, typename enable_if< typename gtl_and< typename is_any_mutable_polygon_without_holes_type<polygon_type>::type, typename gtl_same_type < forty_five_domain, typename geometry_domain<typename geometry_concept<polygon_type>::type>::type>::type>::type>::type * = 0 ) { std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; points.reserve(::boost::polygon::size(polygon)); for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); scale(points.back(), anisotropic_scale_factor<double>(factor, factor)); } snap_point_vector_to_45(points); polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); return polygon; } template <typename T> T& scale(T& polygon, double factor, typename enable_if< typename is_any_mutable_polygon_with_holes_type<T>::type>::type * = 0 ) { typedef typename polygon_with_holes_traits<T>::hole_type hole_type; hole_type h; set_points(h, begin_points(polygon), end_points(polygon)); scale(h, factor); std::vector<hole_type> holes; holes.reserve(size_holes(polygon)); for(typename polygon_with_holes_traits<T>::iterator_holes_type itr = begin_holes(polygon); itr != end_holes(polygon); ++itr) { holes.push_back(*itr); scale(holes.back(), factor); } assign(polygon, h); set_holes(polygon, holes.begin(), holes.end()); return polygon; } template <typename iterator_type, typename area_type> static area_type point_sequence_area(iterator_type begin_range, iterator_type end_range) { typedef typename std::iterator_traits<iterator_type>::value_type point_type; if(begin_range == end_range) return area_type(0); point_type first = *begin_range; point_type previous = first; ++begin_range; // Initialize trapezoid base line area_type y_base = (area_type)y(first); // Initialize area accumulator area_type area(0); while (begin_range != end_range) { area_type x1 = (area_type)x(previous); area_type x2 = (area_type)x(*begin_range); #ifdef BOOST_POLYGON_ICC #pragma warning (push) #pragma warning (disable:1572) #endif if(x1 != x2) { #ifdef BOOST_POLYGON_ICC #pragma warning (pop) #endif // do trapezoid area accumulation area += (x2 - x1) * (((area_type)y(*begin_range) - y_base) + ((area_type)y(previous) - y_base)) / 2; } previous = *begin_range; // go to next point ++begin_range; } //wrap around to evaluate the edge between first and last if not closed if(!equivalence(first, previous)) { area_type x1 = (area_type)x(previous); area_type x2 = (area_type)x(first); area += (x2 - x1) * (((area_type)y(first) - y_base) + ((area_type)y(previous) - y_base)) / 2; } return area; } template <typename T> typename enable_if< typename is_polygon_with_holes_type<T>::type, typename area_type_by_domain< typename geometry_domain<typename geometry_concept<T>::type>::type, typename polygon_traits<T>::coordinate_type>::type>::type area(const T& polygon) { typedef typename area_type_by_domain< typename geometry_domain<typename geometry_concept<T>::type>::type, typename polygon_traits<T>::coordinate_type>::type area_type; area_type retval = point_sequence_area<typename polygon_traits<T>::iterator_type, area_type> (begin_points(polygon), end_points(polygon)); if(retval < 0) retval *= -1; for(typename polygon_with_holes_traits<T>::iterator_holes_type itr = polygon_with_holes_traits<T>::begin_holes(polygon); itr != polygon_with_holes_traits<T>::end_holes(polygon); ++itr) { area_type tmp_area = point_sequence_area <typename polygon_traits<typename polygon_with_holes_traits<T>::hole_type>::iterator_type, area_type> (begin_points(*itr), end_points(*itr)); if(tmp_area < 0) tmp_area *= -1; retval -= tmp_area; } return retval; } template <typename iT> bool point_sequence_is_45(iT itr, iT itr_end) { typedef typename std::iterator_traits<iT>::value_type Point; typedef typename point_traits<Point>::coordinate_type Unit; if(itr == itr_end) return true; Point firstPt = *itr; Point prevPt = firstPt; ++itr; while(itr != itr_end) { Point pt = *itr; Unit deltax = x(pt) - x(prevPt); Unit deltay = y(pt) - y(prevPt); if(deltax && deltay && local_abs(deltax) != local_abs(deltay)) return false; prevPt = pt; ++itr; } Unit deltax = x(firstPt) - x(prevPt); Unit deltay = y(firstPt) - y(prevPt); if(deltax && deltay && local_abs(deltax) != local_abs(deltay)) return false; return true; } template <typename polygon_type> typename enable_if< typename is_polygon_with_holes_type<polygon_type>::type, bool>::type is_45(const polygon_type& polygon) { typename polygon_traits<polygon_type>::iterator_type itr = begin_points(polygon), itr_end = end_points(polygon); if(!point_sequence_is_45(itr, itr_end)) return false; typename polygon_with_holes_traits<polygon_type>::iterator_holes_type itrh = begin_holes(polygon), itrh_end = end_holes(polygon); typedef typename polygon_with_holes_traits<polygon_type>::hole_type hole_type; for(; itrh != itrh_end; ++ itrh) { typename polygon_traits<hole_type>::iterator_type itr1 = begin_points(polygon), itr1_end = end_points(polygon); if(!point_sequence_is_45(itr1, itr1_end)) return false; } return true; } template <typename distance_type, typename iterator_type> distance_type point_sequence_distance(iterator_type itr, iterator_type itr_end) { typedef distance_type Unit; typedef iterator_type iterator; typedef typename std::iterator_traits<iterator>::value_type point_type; Unit return_value = Unit(0); point_type previous_point, first_point; if(itr == itr_end) return return_value; previous_point = first_point = *itr; ++itr; for( ; itr != itr_end; ++itr) { point_type current_point = *itr; return_value += (Unit)euclidean_distance(current_point, previous_point); previous_point = current_point; } return_value += (Unit)euclidean_distance(previous_point, first_point); return return_value; } template <typename T> typename distance_type_by_domain <typename geometry_domain<typename geometry_concept<T>::type>::type, typename polygon_traits<T>::coordinate_type>::type perimeter(const T& polygon, typename enable_if< typename is_polygon_with_holes_type<T>::type>::type * = 0 ) { typedef typename distance_type_by_domain <typename geometry_domain<typename geometry_concept<T>::type>::type, typename polygon_traits<T>::coordinate_type>::type Unit; typedef typename polygon_traits<T>::iterator_type iterator; iterator itr = begin_points(polygon); iterator itr_end = end_points(polygon); Unit return_value = point_sequence_distance<Unit, iterator>(itr, itr_end); for(typename polygon_with_holes_traits<T>::iterator_holes_type itr_holes = begin_holes(polygon); itr_holes != end_holes(polygon); ++itr_holes) { typedef typename polygon_traits<typename polygon_with_holes_traits<T>::hole_type>::iterator_type hitertype; return_value += point_sequence_distance<Unit, hitertype>(begin_points(*itr_holes), end_points(*itr_holes)); } return return_value; } template <typename T> typename enable_if <typename is_polygon_with_holes_type<T>::type, direction_1d>::type winding(const T& polygon) { winding_direction wd = polygon_traits<T>::winding(polygon); if(wd != unknown_winding) { return wd == clockwise_winding ? CLOCKWISE: COUNTERCLOCKWISE; } typedef typename area_type_by_domain< typename geometry_domain<typename geometry_concept<T>::type>::type, typename polygon_traits<T>::coordinate_type>::type area_type; return point_sequence_area<typename polygon_traits<T>::iterator_type, area_type>(begin_points(polygon), end_points(polygon)) < 0 ? COUNTERCLOCKWISE : CLOCKWISE; } template <typename T, typename input_point_type> typename enable_if< typename gtl_and< typename is_polygon_90_type<T>::type, typename gtl_same_type< typename geometry_concept<input_point_type>::type, point_concept >::type >::type, bool >::type contains( const T& polygon, const input_point_type& point, bool consider_touch = true) { typedef T polygon_type; typedef typename polygon_traits<polygon_type>::coordinate_type coordinate_type; typedef typename polygon_traits<polygon_type>::iterator_type iterator; typedef typename std::iterator_traits<iterator>::value_type point_type; coordinate_type point_x = x(point); coordinate_type point_y = y(point); // Check how many intersections has the ray extended from the given // point in the x-axis negative direction with the polygon edges. // If the number is odd the point is within the polygon, otherwise not. // We can safely ignore horizontal edges, however intersections with // end points of the vertical edges require special handling. We should // add one intersection in case horizontal edges that extend vertical edge // point in the same direction. int num_full_intersections = 0; int num_half_intersections = 0; for (iterator iter = begin_points(polygon); iter != end_points(polygon);) { point_type curr_point = *iter; ++iter; point_type next_point = (iter == end_points(polygon)) ? *begin_points(polygon) : *iter; if (x(curr_point) == x(next_point)) { if (x(curr_point) > point_x) { continue; } coordinate_type min_y = (std::min)(y(curr_point), y(next_point)); coordinate_type max_y = (std::max)(y(curr_point), y(next_point)); if (point_y > min_y && point_y < max_y) { if (x(curr_point) == point_x) { return consider_touch; } ++num_full_intersections; } if (point_y == min_y || point_y == max_y) { num_half_intersections += (y(curr_point) < y(next_point) ? 1 : -1); } } else { coordinate_type min_x = (std::min)(x(curr_point), x(next_point)); coordinate_type max_x = (std::max)(x(curr_point), x(next_point)); if (point_x >= min_x && point_x <= max_x) { if (y(curr_point) == point_y) { return consider_touch; } } } } int total_intersections = num_full_intersections + (num_half_intersections >> 1); return total_intersections & 1; } //TODO: refactor to expose as user APIs template <typename Unit> struct edge_utils { typedef point_data<Unit> Point; typedef std::pair<Point, Point> half_edge; class less_point { public: typedef Point first_argument_type; typedef Point second_argument_type; typedef bool result_type; inline less_point() {} inline bool operator () (const Point& pt1, const Point& pt2) const { if(pt1.get(HORIZONTAL) < pt2.get(HORIZONTAL)) return true; if(pt1.get(HORIZONTAL) == pt2.get(HORIZONTAL)) { if(pt1.get(VERTICAL) < pt2.get(VERTICAL)) return true; } return false; } }; static inline bool between(Point pt, Point pt1, Point pt2) { less_point lp; if(lp(pt1, pt2)) return lp(pt, pt2) && lp(pt1, pt); return lp(pt, pt1) && lp(pt2, pt); } template <typename area_type> static inline bool equal_slope(area_type dx1, area_type dy1, area_type dx2, area_type dy2) { typedef typename coordinate_traits<Unit>::unsigned_area_type unsigned_product_type; unsigned_product_type cross_1 = (unsigned_product_type)(dx2 < 0 ? -dx2 :dx2) * (unsigned_product_type)(dy1 < 0 ? -dy1 : dy1); unsigned_product_type cross_2 = (unsigned_product_type)(dx1 < 0 ? -dx1 :dx1) * (unsigned_product_type)(dy2 < 0 ? -dy2 : dy2); int dx1_sign = dx1 < 0 ? -1 : 1; int dx2_sign = dx2 < 0 ? -1 : 1; int dy1_sign = dy1 < 0 ? -1 : 1; int dy2_sign = dy2 < 0 ? -1 : 1; int cross_1_sign = dx2_sign * dy1_sign; int cross_2_sign = dx1_sign * dy2_sign; return cross_1 == cross_2 && (cross_1_sign == cross_2_sign || cross_1 == 0); } static inline bool equal_slope(const Unit& x, const Unit& y, const Point& pt1, const Point& pt2) { const Point* pts[2] = {&pt1, &pt2}; typedef typename coordinate_traits<Unit>::manhattan_area_type at; at dy2 = (at)pts[1]->get(VERTICAL) - (at)y; at dy1 = (at)pts[0]->get(VERTICAL) - (at)y; at dx2 = (at)pts[1]->get(HORIZONTAL) - (at)x; at dx1 = (at)pts[0]->get(HORIZONTAL) - (at)x; return equal_slope(dx1, dy1, dx2, dy2); } template <typename area_type> static inline bool less_slope(area_type dx1, area_type dy1, area_type dx2, area_type dy2) { //reflext x and y slopes to right hand side half plane if(dx1 < 0) { dy1 *= -1; dx1 *= -1; } else if(dx1 == 0) { //if the first slope is vertical the first cannot be less return false; } if(dx2 < 0) { dy2 *= -1; dx2 *= -1; } else if(dx2 == 0) { //if the second slope is vertical the first is always less unless it is also vertical, in which case they are equal return dx1 != 0; } typedef typename coordinate_traits<Unit>::unsigned_area_type unsigned_product_type; unsigned_product_type cross_1 = (unsigned_product_type)(dx2 < 0 ? -dx2 :dx2) * (unsigned_product_type)(dy1 < 0 ? -dy1 : dy1); unsigned_product_type cross_2 = (unsigned_product_type)(dx1 < 0 ? -dx1 :dx1) * (unsigned_product_type)(dy2 < 0 ? -dy2 : dy2); int dx1_sign = dx1 < 0 ? -1 : 1; int dx2_sign = dx2 < 0 ? -1 : 1; int dy1_sign = dy1 < 0 ? -1 : 1; int dy2_sign = dy2 < 0 ? -1 : 1; int cross_1_sign = dx2_sign * dy1_sign; int cross_2_sign = dx1_sign * dy2_sign; if(cross_1_sign < cross_2_sign) return true; if(cross_2_sign < cross_1_sign) return false; if(cross_1_sign == -1) return cross_2 < cross_1; return cross_1 < cross_2; } static inline bool less_slope(const Unit& x, const Unit& y, const Point& pt1, const Point& pt2) { const Point* pts[2] = {&pt1, &pt2}; //compute y value on edge from pt_ to pts[1] at the x value of pts[0] typedef typename coordinate_traits<Unit>::manhattan_area_type at; at dy2 = (at)pts[1]->get(VERTICAL) - (at)y; at dy1 = (at)pts[0]->get(VERTICAL) - (at)y; at dx2 = (at)pts[1]->get(HORIZONTAL) - (at)x; at dx1 = (at)pts[0]->get(HORIZONTAL) - (at)x; return less_slope(dx1, dy1, dx2, dy2); } //return -1 below, 0 on and 1 above line //assumes point is on x interval of segment static inline int on_above_or_below(Point pt, const half_edge& he) { if(pt == he.first || pt == he.second) return 0; if(equal_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), he.first, he.second)) return 0; bool less_result = less_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), he.first, he.second); int retval = less_result ? -1 : 1; less_point lp; if(lp(he.second, he.first)) retval *= -1; if(!between(pt, he.first, he.second)) retval *= -1; return retval; } }; template <typename T, typename input_point_type> typename enable_if< typename gtl_and< typename is_any_mutable_polygon_with_holes_type<T>::type, typename gtl_same_type<typename geometry_concept<input_point_type>::type, point_concept>::type>::type, bool>::type contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { typedef typename polygon_with_holes_traits<T>::iterator_holes_type holes_iterator; bool isInside = contains( view_as< typename polygon_from_polygon_with_holes_type< typename geometry_concept<T>::type>::type>( polygon ), point, consider_touch ); if(!isInside) return false; //no need to check holes holes_iterator itH = begin_holes( polygon ); while( itH != end_holes( polygon ) ) { if( contains( *itH, point, !consider_touch ) ) { isInside = false; break; } ++itH; } return isInside; } template <typename T, typename input_point_type> typename enable_if< typename gtl_and_3< typename is_polygon_type<T>::type, typename gtl_different_type<typename geometry_domain<typename geometry_concept<T>::type>::type, manhattan_domain>::type, typename gtl_same_type<typename geometry_concept<input_point_type>::type, point_concept>::type>::type, bool>::type contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { typedef typename point_traits<input_point_type>::coordinate_type Unit; typedef point_data<Unit> Point; typedef std::pair<Point, Point> half_edge; typedef typename polygon_traits<T>::iterator_type iterator; iterator itr = begin_points(polygon); iterator itrEnd = end_points(polygon); half_edge he; if(itr == itrEnd) return false; assign(he.first, *itr); Point firstPt; assign(firstPt, *itr); ++itr; if(itr == itrEnd) return false; bool done = false; int above = 0; while(!done) { Point currentPt; if(itr == itrEnd) { done = true; currentPt = firstPt; } else { assign(currentPt, *itr); ++itr; } if(currentPt == he.first) { continue; } else { he.second = currentPt; if(equivalence(point, currentPt)) return consider_touch; Unit xmin = (std::min)(x(he.first), x(he.second)); Unit xmax = (std::max)(x(he.first), x(he.second)); if(x(point) >= xmin && x(point) < xmax) { //double counts if <= xmax Point tmppt; assign(tmppt, point); int oabedge = edge_utils<Unit>::on_above_or_below(tmppt, he); if(oabedge == 0) return consider_touch; if(oabedge == 1) ++above; } else if(x(point) == xmax) { if(x(point) == xmin) { Unit ymin = (std::min)(y(he.first), y(he.second)); Unit ymax = (std::max)(y(he.first), y(he.second)); Unit ypt = y(point); if(ypt <= ymax && ypt >= ymin) return consider_touch; } else { Point tmppt; assign(tmppt, point); if( edge_utils<Unit>::on_above_or_below(tmppt, he) == 0 ) { return consider_touch; } } } } he.first = he.second; } return above % 2 != 0; //if the point is above an odd number of edges is must be inside polygon } /* template <typename T, typename input_point_type> typename enable_if< typename gtl_and_3< typename is_polygon_with_holes_type<T>::type, typename gtl_different_type<typename geometry_domain<typename geometry_concept<T>::type>::type, manhattan_domain>::type, typename gtl_same_type<typename geometry_concept<input_point_type>::type, point_concept>::type>::type, bool>::type contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { typedef typename point_traits<input_point_type>::coordinate_type Unit; typedef point_data<Unit> Point; typedef std::pair<Point, Point> half_edge; typedef typename polygon_traits<T>::iterator_type iterator; iterator itr = begin_points(polygon); iterator itrEnd = end_points(polygon); half_edge he; if(itr == itrEnd) return false; assign(he.first, *itr); Point firstPt; assign(firstPt, *itr); ++itr; if(itr == itrEnd) return false; bool done = false; int above = 0; while(!done) { Point currentPt; if(itr == itrEnd) { done = true; currentPt = firstPt; } else { assign(currentPt, *itr); ++itr; } if(currentPt == he.first) { continue; } else { he.second = currentPt; if(equivalence(point, currentPt)) return consider_touch; Unit xmin = (std::min)(x(he.first), x(he.second)); Unit xmax = (std::max)(x(he.first), x(he.second)); if(x(point) >= xmin && x(point) < xmax) { //double counts if <= xmax Point tmppt; assign(tmppt, point); int oabedge = edge_utils<Unit>::on_above_or_below(tmppt, he); if(oabedge == 0) return consider_touch; if(oabedge == 1) ++above; } } he.first = he.second; } return above % 2 != 0; //if the point is above an odd number of edges is must be inside polygon } */ template <typename T1, typename T2> typename enable_if< typename gtl_and< typename is_mutable_rectangle_concept<typename geometry_concept<T1>::type>::type, typename is_polygon_with_holes_type<T2>::type>::type, bool>::type extents(T1& bounding_box, const T2& polygon) { typedef typename polygon_traits<T2>::iterator_type iterator; bool first_iteration = true; iterator itr_end = end_points(polygon); for(iterator itr = begin_points(polygon); itr != itr_end; ++itr) { if(first_iteration) { set_points(bounding_box, *itr, *itr); first_iteration = false; } else { encompass(bounding_box, *itr); } } if(first_iteration) return false; return true; } template <typename T1, typename T2> typename enable_if< typename gtl_and< typename is_mutable_point_concept<typename geometry_concept<T1>::type>::type, typename is_polygon_with_holes_type<T2>::type>::type, bool>::type center(T1& center_point, const T2& polygon) { typedef typename polygon_traits<T2>::coordinate_type coordinate_type; rectangle_data<coordinate_type> bbox; extents(bbox, polygon); return center(center_point, bbox); } template <class T> template <class T2> polygon_90_data<T>& polygon_90_data<T>::operator=(const T2& rvalue) { assign(*this, rvalue); return *this; } template <class T> template <class T2> polygon_45_data<T>& polygon_45_data<T>::operator=(const T2& rvalue) { assign(*this, rvalue); return *this; } template <class T> template <class T2> polygon_data<T>& polygon_data<T>::operator=(const T2& rvalue) { assign(*this, rvalue); return *this; } template <class T> template <class T2> polygon_90_with_holes_data<T>& polygon_90_with_holes_data<T>::operator=(const T2& rvalue) { assign(*this, rvalue); return *this; } template <class T> template <class T2> polygon_45_with_holes_data<T>& polygon_45_with_holes_data<T>::operator=(const T2& rvalue) { assign(*this, rvalue); return *this; } template <class T> template <class T2> polygon_with_holes_data<T>& polygon_with_holes_data<T>::operator=(const T2& rvalue) { assign(*this, rvalue); return *this; } template <typename T> struct geometry_concept<polygon_data<T> > { typedef polygon_concept type; }; template <typename T> struct geometry_concept<polygon_45_data<T> > { typedef polygon_45_concept type; }; template <typename T> struct geometry_concept<polygon_90_data<T> > { typedef polygon_90_concept type; }; template <typename T> struct geometry_concept<polygon_with_holes_data<T> > { typedef polygon_with_holes_concept type; }; template <typename T> struct geometry_concept<polygon_45_with_holes_data<T> > { typedef polygon_45_with_holes_concept type; }; template <typename T> struct geometry_concept<polygon_90_with_holes_data<T> > { typedef polygon_90_with_holes_concept type; }; // template <typename T> struct polygon_with_holes_traits<polygon_90_data<T> > { // typedef polygon_90_data<T> hole_type; // typedef const hole_type* iterator_holes_type; // static inline iterator_holes_type begin_holes(const hole_type& t) { return &t; } // static inline iterator_holes_type end_holes(const hole_type& t) { return &t; } // static inline std::size_t size_holes(const hole_type& t) { return 0; } // }; // template <typename T> struct polygon_with_holes_traits<polygon_45_data<T> > { // typedef polygon_45_data<T> hole_type; // typedef const hole_type* iterator_holes_type; // static inline iterator_holes_type begin_holes(const hole_type& t) { return &t; } // static inline iterator_holes_type end_holes(const hole_type& t) { return &t; } // static inline std::size_t size_holes(const hole_type& t) { return 0; } // }; // template <typename T> struct polygon_with_holes_traits<polygon_data<T> > { // typedef polygon_data<T> hole_type; // typedef const hole_type* iterator_holes_type; // static inline iterator_holes_type begin_holes(const hole_type& t) { return &t; } // static inline iterator_holes_type end_holes(const hole_type& t) { return &t; } // static inline std::size_t size_holes(const hole_type& t) { return 0; } // }; template <typename T> struct get_void {}; template <> struct get_void<gtl_yes> { typedef void type; }; template <typename T> struct polygon_with_holes_traits< T, typename get_void<typename is_any_mutable_polygon_without_holes_type<T>::type>::type > { typedef T hole_type; typedef const hole_type* iterator_holes_type; static inline iterator_holes_type begin_holes(const hole_type& t) { return &t; } static inline iterator_holes_type end_holes(const hole_type& t) { return &t; } }; template <typename T> struct view_of<rectangle_concept, T> { typedef typename polygon_traits<T>::coordinate_type coordinate_type; typedef interval_data<coordinate_type> interval_type; rectangle_data<coordinate_type> rect; view_of(const T& obj) : rect() { point_data<coordinate_type> pts[2]; typename polygon_traits<T>::iterator_type itr = begin_points(obj), itre = end_points(obj); if(itr == itre) return; assign(pts[0], *itr); ++itr; if(itr == itre) return; ++itr; if(itr == itre) return; assign(pts[1], *itr); set_points(rect, pts[0], pts[1]); } inline interval_type get(orientation_2d orient) const { return rect.get(orient); } }; template <typename T> struct geometry_concept<view_of<rectangle_concept, T> > { typedef rectangle_concept type; }; template <typename T> struct view_of<polygon_45_concept, T> { const T* t; view_of(const T& obj) : t(&obj) {} typedef typename polygon_traits<T>::coordinate_type coordinate_type; typedef typename polygon_traits<T>::iterator_type iterator_type; typedef typename polygon_traits<T>::point_type point_type; /// Get the begin iterator inline iterator_type begin() const { return polygon_traits<T>::begin_points(*t); } /// Get the end iterator inline iterator_type end() const { return polygon_traits<T>::end_points(*t); } /// Get the number of sides of the polygon inline std::size_t size() const { return polygon_traits<T>::size(*t); } /// Get the winding direction of the polygon inline winding_direction winding() const { return polygon_traits<T>::winding(*t); } }; template <typename T> struct geometry_concept<view_of<polygon_45_concept, T> > { typedef polygon_45_concept type; }; template <typename T> struct view_of<polygon_90_concept, T> { const T* t; view_of(const T& obj) : t(&obj) {} typedef typename polygon_traits<T>::coordinate_type coordinate_type; typedef typename polygon_traits<T>::iterator_type iterator_type; typedef typename polygon_traits<T>::point_type point_type; typedef iterator_points_to_compact<iterator_type, point_type> compact_iterator_type; /// Get the begin iterator inline compact_iterator_type begin_compact() const { return compact_iterator_type(polygon_traits<T>::begin_points(*t), polygon_traits<T>::end_points(*t)); } /// Get the end iterator inline compact_iterator_type end_compact() const { return compact_iterator_type(polygon_traits<T>::end_points(*t), polygon_traits<T>::end_points(*t)); } /// Get the number of sides of the polygon inline std::size_t size() const { return polygon_traits<T>::size(*t); } /// Get the winding direction of the polygon inline winding_direction winding() const { return polygon_traits<T>::winding(*t); } }; template <typename T> struct geometry_concept<view_of<polygon_90_concept, T> > { typedef polygon_90_concept type; }; template <typename T> struct view_of<polygon_45_with_holes_concept, T> { const T* t; view_of(const T& obj) : t(&obj) {} typedef typename polygon_traits<T>::coordinate_type coordinate_type; typedef typename polygon_traits<T>::iterator_type iterator_type; typedef typename polygon_traits<T>::point_type point_type; typedef view_of<polygon_45_concept, typename polygon_with_holes_traits<T>::hole_type> hole_type; struct iterator_holes_type { typedef std::forward_iterator_tag iterator_category; typedef hole_type value_type; typedef std::ptrdiff_t difference_type; typedef const hole_type* pointer; //immutable typedef const hole_type& reference; //immutable typedef typename polygon_with_holes_traits<T>::iterator_holes_type iht; iht internal_itr; iterator_holes_type() : internal_itr() {} iterator_holes_type(iht iht_in) : internal_itr(iht_in) {} inline iterator_holes_type& operator++() { ++internal_itr; return *this; } inline const iterator_holes_type operator++(int) { iterator_holes_type tmp(*this); ++(*this); return tmp; } inline bool operator==(const iterator_holes_type& that) const { return (internal_itr == that.internal_itr); } inline bool operator!=(const iterator_holes_type& that) const { return (internal_itr != that.internal_itr); } inline value_type operator*() const { return view_as<polygon_45_concept>(*internal_itr); } }; /// Get the begin iterator inline iterator_type begin() const { return polygon_traits<T>::begin_points(*t); } /// Get the end iterator inline iterator_type end() const { return polygon_traits<T>::end_points(*t); } /// Get the number of sides of the polygon inline std::size_t size() const { return polygon_traits<T>::size(*t); } /// Get the winding direction of the polygon inline winding_direction winding() const { return polygon_traits<T>::winding(*t); } /// Get the begin iterator inline iterator_holes_type begin_holes() const { return polygon_with_holes_traits<T>::begin_holes(*t); } /// Get the end iterator inline iterator_holes_type end_holes() const { return polygon_with_holes_traits<T>::end_holes(*t); } /// Get the number of sides of the polygon inline std::size_t size_holes() const { return polygon_with_holes_traits<T>::size_holes(*t); } }; template <typename T> struct geometry_concept<view_of<polygon_45_with_holes_concept, T> > { typedef polygon_45_with_holes_concept type; }; template <typename T> struct view_of<polygon_90_with_holes_concept, T> { const T* t; view_of(const T& obj) : t(&obj) {} typedef typename polygon_traits<T>::coordinate_type coordinate_type; typedef typename polygon_traits<T>::iterator_type iterator_type; typedef typename polygon_traits<T>::point_type point_type; typedef iterator_points_to_compact<iterator_type, point_type> compact_iterator_type; typedef view_of<polygon_90_concept, typename polygon_with_holes_traits<T>::hole_type> hole_type; struct iterator_holes_type { typedef std::forward_iterator_tag iterator_category; typedef hole_type value_type; typedef std::ptrdiff_t difference_type; typedef const hole_type* pointer; //immutable typedef const hole_type& reference; //immutable typedef typename polygon_with_holes_traits<T>::iterator_holes_type iht; iht internal_itr; iterator_holes_type() : internal_itr() {} iterator_holes_type(iht iht_in) : internal_itr(iht_in) {} inline iterator_holes_type& operator++() { ++internal_itr; return *this; } inline const iterator_holes_type operator++(int) { iterator_holes_type tmp(*this); ++(*this); return tmp; } inline bool operator==(const iterator_holes_type& that) const { return (internal_itr == that.internal_itr); } inline bool operator!=(const iterator_holes_type& that) const { return (internal_itr != that.internal_itr); } inline value_type operator*() const { return view_as<polygon_90_concept>(*internal_itr); } }; /// Get the begin iterator inline compact_iterator_type begin_compact() const { return compact_iterator_type(polygon_traits<T>::begin_points(*t), polygon_traits<T>::end_points(*t)); } /// Get the end iterator inline compact_iterator_type end_compact() const { return compact_iterator_type(polygon_traits<T>::end_points(*t), polygon_traits<T>::end_points(*t)); } /// Get the number of sides of the polygon inline std::size_t size() const { return polygon_traits<T>::size(*t); } /// Get the winding direction of the polygon inline winding_direction winding() const { return polygon_traits<T>::winding(*t); } /// Get the begin iterator inline iterator_holes_type begin_holes() const { return polygon_with_holes_traits<T>::begin_holes(*t); } /// Get the end iterator inline iterator_holes_type end_holes() const { return polygon_with_holes_traits<T>::end_holes(*t); } /// Get the number of sides of the polygon inline std::size_t size_holes() const { return polygon_with_holes_traits<T>::size_holes(*t); } }; template <typename T> struct geometry_concept<view_of<polygon_90_with_holes_concept, T> > { typedef polygon_90_with_holes_concept type; }; template <typename T> struct view_of<polygon_concept, T> { const T* t; view_of(const T& obj) : t(&obj) {} typedef typename polygon_traits<T>::coordinate_type coordinate_type; typedef typename polygon_traits<T>::iterator_type iterator_type; typedef typename polygon_traits<T>::point_type point_type; /// Get the begin iterator inline iterator_type begin() const { return polygon_traits<T>::begin_points(*t); } /// Get the end iterator inline iterator_type end() const { return polygon_traits<T>::end_points(*t); } /// Get the number of sides of the polygon inline std::size_t size() const { return polygon_traits<T>::size(*t); } /// Get the winding direction of the polygon inline winding_direction winding() const { return polygon_traits<T>::winding(*t); } }; template <typename T> struct geometry_concept<view_of<polygon_concept, T> > { typedef polygon_concept type; }; } } #endif detail/rectangle_formation.hpp 0000644 00000027776 15125572616 0012576 0 ustar 00 /* 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_RECTANGLE_FORMATION_HPP #define BOOST_POLYGON_RECTANGLE_FORMATION_HPP namespace boost { namespace polygon{ namespace rectangle_formation { template <class T> class ScanLineToRects { public: typedef T rectangle_type; typedef typename rectangle_traits<T>::coordinate_type coordinate_type; typedef rectangle_data<coordinate_type> scan_rect_type; private: typedef std::set<scan_rect_type, less_rectangle_concept<scan_rect_type, scan_rect_type> > ScanData; ScanData scanData_; bool haveCurrentRect_; scan_rect_type currentRect_; orientation_2d orient_; typename rectangle_traits<T>::coordinate_type currentCoordinate_; public: inline ScanLineToRects() : scanData_(), haveCurrentRect_(), currentRect_(), orient_(), currentCoordinate_() {} inline ScanLineToRects(orientation_2d orient, rectangle_type model) : scanData_(orientation_2d(orient.to_int() ? VERTICAL : HORIZONTAL)), haveCurrentRect_(false), currentRect_(), orient_(orient), currentCoordinate_() { assign(currentRect_, model); currentCoordinate_ = (std::numeric_limits<coordinate_type>::max)(); } template <typename CT> inline ScanLineToRects& processEdge(CT& rectangles, const interval_data<coordinate_type>& edge); inline ScanLineToRects& nextMajorCoordinate(coordinate_type currentCoordinate) { if(haveCurrentRect_) { scanData_.insert(scanData_.end(), currentRect_); haveCurrentRect_ = false; } currentCoordinate_ = currentCoordinate; return *this; } }; template <class CT, class ST, class rectangle_type, typename interval_type, typename coordinate_type> inline CT& processEdge_(CT& rectangles, ST& scanData, const interval_type& edge, bool& haveCurrentRect, rectangle_type& currentRect, coordinate_type currentCoordinate, orientation_2d orient) { typedef typename CT::value_type result_type; bool edgeProcessed = false; if(!scanData.empty()) { //process all rectangles in the scanData that touch the edge typename ST::iterator dataIter = scanData.lower_bound(rectangle_type(edge, edge)); //decrement beginIter until its low is less than edge's low while((dataIter == scanData.end() || (*dataIter).get(orient).get(LOW) > edge.get(LOW)) && dataIter != scanData.begin()) { --dataIter; } //process each rectangle until the low end of the rectangle //is greater than the high end of the edge while(dataIter != scanData.end() && (*dataIter).get(orient).get(LOW) <= edge.get(HIGH)) { const rectangle_type& rect = *dataIter; //if the rectangle data intersects the edge at all if(rect.get(orient).get(HIGH) >= edge.get(LOW)) { if(contains(rect.get(orient), edge, true)) { //this is a closing edge //we need to write out the intersecting rectangle and //insert between 0 and 2 rectangles into the scanData //write out rectangle rectangle_type tmpRect = rect; if(rect.get(orient.get_perpendicular()).get(LOW) < currentCoordinate) { //set the high coordinate perpedicular to slicing orientation //to the current coordinate of the scan event tmpRect.set(orient.get_perpendicular().get_direction(HIGH), currentCoordinate); result_type result; assign(result, tmpRect); rectangles.insert(rectangles.end(), result); } //erase the rectangle from the scan data typename ST::iterator nextIter = dataIter; ++nextIter; scanData.erase(dataIter); if(tmpRect.get(orient).get(LOW) < edge.get(LOW)) { //insert a rectangle for the overhang of the bottom //of the rectangle back into scan data rectangle_type lowRect(tmpRect); lowRect.set(orient.get_perpendicular(), interval_data<coordinate_type>(currentCoordinate, currentCoordinate)); lowRect.set(orient.get_direction(HIGH), edge.get(LOW)); scanData.insert(nextIter, lowRect); } if(tmpRect.get(orient).get(HIGH) > edge.get(HIGH)) { //insert a rectangle for the overhang of the top //of the rectangle back into scan data rectangle_type highRect(tmpRect); highRect.set(orient.get_perpendicular(), interval_data<coordinate_type>(currentCoordinate, currentCoordinate)); highRect.set(orient.get_direction(LOW), edge.get(HIGH)); scanData.insert(nextIter, highRect); } //we are done with this edge edgeProcessed = true; break; } else { //it must be an opening edge //assert that rect does not overlap the edge but only touches //write out rectangle rectangle_type tmpRect = rect; //set the high coordinate perpedicular to slicing orientation //to the current coordinate of the scan event if(tmpRect.get(orient.get_perpendicular().get_direction(LOW)) < currentCoordinate) { tmpRect.set(orient.get_perpendicular().get_direction(HIGH), currentCoordinate); result_type result; assign(result, tmpRect); rectangles.insert(rectangles.end(), result); } //erase the rectangle from the scan data typename ST::iterator nextIter = dataIter; ++nextIter; scanData.erase(dataIter); dataIter = nextIter; if(haveCurrentRect) { if(currentRect.get(orient).get(HIGH) >= edge.get(LOW)){ if(!edgeProcessed && currentRect.get(orient.get_direction(HIGH)) > edge.get(LOW)){ rectangle_type tmpRect2(currentRect); tmpRect2.set(orient.get_direction(HIGH), edge.get(LOW)); scanData.insert(nextIter, tmpRect2); if(currentRect.get(orient.get_direction(HIGH)) > edge.get(HIGH)) { currentRect.set(orient, interval_data<coordinate_type>(edge.get(HIGH), currentRect.get(orient.get_direction(HIGH)))); } else { haveCurrentRect = false; } } else { //extend the top of current rect currentRect.set(orient.get_direction(HIGH), (std::max)(edge.get(HIGH), tmpRect.get(orient.get_direction(HIGH)))); } } else { //insert current rect into the scanData scanData.insert(nextIter, currentRect); //create a new current rect currentRect.set(orient.get_perpendicular(), interval_data<coordinate_type>(currentCoordinate, currentCoordinate)); currentRect.set(orient, interval_data<coordinate_type>((std::min)(tmpRect.get(orient).get(LOW), edge.get(LOW)), (std::max)(tmpRect.get(orient).get(HIGH), edge.get(HIGH)))); } } else { haveCurrentRect = true; currentRect.set(orient.get_perpendicular(), interval_data<coordinate_type>(currentCoordinate, currentCoordinate)); currentRect.set(orient, interval_data<coordinate_type>((std::min)(tmpRect.get(orient).get(LOW), edge.get(LOW)), (std::max)(tmpRect.get(orient).get(HIGH), edge.get(HIGH)))); } //skip to nextIter position edgeProcessed = true; continue; } //edgeProcessed = true; } ++dataIter; } //end while edge intersects rectangle data } if(!edgeProcessed) { if(haveCurrentRect) { if(currentRect.get(orient.get_perpendicular().get_direction(HIGH)) == currentCoordinate && currentRect.get(orient.get_direction(HIGH)) >= edge.get(LOW)) { if(currentRect.get(orient.get_direction(HIGH)) > edge.get(LOW)){ rectangle_type tmpRect(currentRect); tmpRect.set(orient.get_direction(HIGH), edge.get(LOW)); scanData.insert(scanData.end(), tmpRect); if(currentRect.get(orient.get_direction(HIGH)) > edge.get(HIGH)) { currentRect.set(orient, interval_data<coordinate_type>(edge.get(HIGH), currentRect.get(orient.get_direction(HIGH)))); return rectangles; } else { haveCurrentRect = false; return rectangles; } } //extend current rect currentRect.set(orient.get_direction(HIGH), edge.get(HIGH)); return rectangles; } scanData.insert(scanData.end(), currentRect); haveCurrentRect = false; } rectangle_type tmpRect(currentRect); tmpRect.set(orient.get_perpendicular(), interval_data<coordinate_type>(currentCoordinate, currentCoordinate)); tmpRect.set(orient, edge); scanData.insert(tmpRect); return rectangles; } return rectangles; } template <class T> template <class CT> inline ScanLineToRects<T>& ScanLineToRects<T>::processEdge(CT& rectangles, const interval_data<coordinate_type>& edge) { processEdge_(rectangles, scanData_, edge, haveCurrentRect_, currentRect_, currentCoordinate_, orient_); return *this; } } //namespace rectangle_formation template <typename T, typename T2> struct get_coordinate_type_for_rectangles { typedef typename polygon_traits<T>::coordinate_type type; }; template <typename T> struct get_coordinate_type_for_rectangles<T, rectangle_concept> { typedef typename rectangle_traits<T>::coordinate_type type; }; template <typename output_container, typename iterator_type, typename rectangle_concept> void form_rectangles(output_container& output, iterator_type begin, iterator_type end, orientation_2d orient, rectangle_concept ) { typedef typename output_container::value_type rectangle_type; typedef typename get_coordinate_type_for_rectangles<rectangle_type, typename geometry_concept<rectangle_type>::type>::type Unit; rectangle_data<Unit> model; Unit prevPos = (std::numeric_limits<Unit>::max)(); rectangle_formation::ScanLineToRects<rectangle_data<Unit> > scanlineToRects(orient, model); for(iterator_type itr = begin; itr != end; ++ itr) { Unit pos = (*itr).first; if(pos != prevPos) { scanlineToRects.nextMajorCoordinate(pos); prevPos = pos; } Unit lowy = (*itr).second.first; iterator_type tmp_itr = itr; ++itr; Unit highy = (*itr).second.first; scanlineToRects.processEdge(output, interval_data<Unit>(lowy, highy)); if(std::abs((*itr).second.second) > 1) itr = tmp_itr; //next edge begins from this vertex } } } } #endif detail/boolean_op.hpp 0000644 00000042254 15125572616 0010655 0 ustar 00 /* 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_BOOLEAN_OP_HPP #define BOOST_POLYGON_BOOLEAN_OP_HPP namespace boost { namespace polygon{ namespace boolean_op { //BooleanOp is the generic boolean operation scanline algorithm that provides //all the simple boolean set operations on manhattan data. By templatizing //the intersection count of the input and algorithm internals it is extensible //to multi-layer scans, properties and other advanced scanline operations above //and beyond simple booleans. //T must cast to int template <class T, typename Unit> class BooleanOp { public: typedef std::map<Unit, T> ScanData; typedef std::pair<Unit, T> ElementType; protected: ScanData scanData_; typename ScanData::iterator nextItr_; T nullT_; public: inline BooleanOp () : scanData_(), nextItr_(), nullT_() { nextItr_ = scanData_.end(); nullT_ = 0; } inline BooleanOp (T nullT) : scanData_(), nextItr_(), nullT_(nullT) { nextItr_ = scanData_.end(); } inline BooleanOp (const BooleanOp& that) : scanData_(that.scanData_), nextItr_(), nullT_(that.nullT_) { nextItr_ = scanData_.begin(); } inline BooleanOp& operator=(const BooleanOp& that); //moves scanline forward inline void advanceScan() { nextItr_ = scanData_.begin(); } //proceses the given interval and T data //appends output edges to cT template <class cT> inline void processInterval(cT& outputContainer, interval_data<Unit> ivl, T deltaCount); private: inline typename ScanData::iterator lookup_(Unit pos){ if(nextItr_ != scanData_.end() && nextItr_->first >= pos) { return nextItr_; } return nextItr_ = scanData_.lower_bound(pos); } inline typename ScanData::iterator insert_(Unit pos, T count){ return nextItr_ = scanData_.insert(nextItr_, ElementType(pos, count)); } template <class cT> inline void evaluateInterval_(cT& outputContainer, interval_data<Unit> ivl, T beforeCount, T afterCount); }; class BinaryAnd { public: inline BinaryAnd() {} inline bool operator()(int a, int b) { return (a > 0) & (b > 0); } }; class BinaryOr { public: inline BinaryOr() {} inline bool operator()(int a, int b) { return (a > 0) | (b > 0); } }; class BinaryNot { public: inline BinaryNot() {} inline bool operator()(int a, int b) { return (a > 0) & !(b > 0); } }; class BinaryXor { public: inline BinaryXor() {} inline bool operator()(int a, int b) { return (a > 0) ^ (b > 0); } }; //BinaryCount is an array of two deltaCounts coming from two different layers //of scan event data. It is the merged count of the two suitable for consumption //as the template argument of the BooleanOp algorithm because BinaryCount casts to int. //T is a binary functor object that evaluates the array of counts and returns a logical //result of some operation on those values. //BinaryCount supports many of the operators that work with int, particularly the //binary operators, but cannot support less than or increment. template <class T> class BinaryCount { public: inline BinaryCount() #ifndef BOOST_POLYGON_MSVC : counts_() #endif { counts_[0] = counts_[1] = 0; } // constructs from two integers inline BinaryCount(int countL, int countR) #ifndef BOOST_POLYGON_MSVC : counts_() #endif { counts_[0] = countL, counts_[1] = countR; } inline BinaryCount& operator=(int count) { counts_[0] = count, counts_[1] = count; return *this; } inline BinaryCount& operator=(const BinaryCount& that); inline BinaryCount(const BinaryCount& that) #ifndef BOOST_POLYGON_MSVC : counts_() #endif { *this = that; } inline bool operator==(const BinaryCount& that) const; inline bool operator!=(const BinaryCount& that) const { return !((*this) == that);} inline BinaryCount& operator+=(const BinaryCount& that); inline BinaryCount& operator-=(const BinaryCount& that); inline BinaryCount operator+(const BinaryCount& that) const; inline BinaryCount operator-(const BinaryCount& that) const; inline BinaryCount operator-() const; inline int& operator[](bool index) { return counts_[index]; } //cast to int operator evaluates data using T binary functor inline operator int() const { return T()(counts_[0], counts_[1]); } private: int counts_[2]; }; class UnaryCount { public: inline UnaryCount() : count_(0) {} // constructs from two integers inline explicit UnaryCount(int count) : count_(count) {} inline UnaryCount& operator=(int count) { count_ = count; return *this; } inline UnaryCount& operator=(const UnaryCount& that) { count_ = that.count_; return *this; } inline UnaryCount(const UnaryCount& that) : count_(that.count_) {} inline bool operator==(const UnaryCount& that) const { return count_ == that.count_; } inline bool operator!=(const UnaryCount& that) const { return !((*this) == that);} inline UnaryCount& operator+=(const UnaryCount& that) { count_ += that.count_; return *this; } inline UnaryCount& operator-=(const UnaryCount& that) { count_ -= that.count_; return *this; } inline UnaryCount operator+(const UnaryCount& that) const { UnaryCount tmp(*this); tmp += that; return tmp; } inline UnaryCount operator-(const UnaryCount& that) const { UnaryCount tmp(*this); tmp -= that; return tmp; } inline UnaryCount operator-() const { UnaryCount tmp; return tmp - *this; } //cast to int operator evaluates data using T binary functor inline operator int() const { return count_ % 2; } private: int count_; }; template <class T, typename Unit> inline BooleanOp<T, Unit>& BooleanOp<T, Unit>::operator=(const BooleanOp& that) { scanData_ = that.scanData_; nextItr_ = scanData_.begin(); nullT_ = that.nullT_; return *this; } //appends output edges to cT template <class T, typename Unit> template <class cT> inline void BooleanOp<T, Unit>::processInterval(cT& outputContainer, interval_data<Unit> ivl, T deltaCount) { typename ScanData::iterator lowItr = lookup_(ivl.low()); typename ScanData::iterator highItr = lookup_(ivl.high()); //add interval to scan data if it is past the end if(lowItr == scanData_.end()) { lowItr = insert_(ivl.low(), deltaCount); highItr = insert_(ivl.high(), nullT_); evaluateInterval_(outputContainer, ivl, nullT_, deltaCount); return; } //ensure that highItr points to the end of the ivl if(highItr == scanData_.end() || (*highItr).first > ivl.high()) { T value = nullT_; if(highItr != scanData_.begin()) { --highItr; value = highItr->second; } nextItr_ = highItr; highItr = insert_(ivl.high(), value); } //split the low interval if needed if(lowItr->first > ivl.low()) { if(lowItr != scanData_.begin()) { --lowItr; nextItr_ = lowItr; lowItr = insert_(ivl.low(), lowItr->second); } else { nextItr_ = lowItr; lowItr = insert_(ivl.low(), nullT_); } } //process scan data intersecting interval for(typename ScanData::iterator itr = lowItr; itr != highItr; ){ T beforeCount = itr->second; T afterCount = itr->second += deltaCount; Unit low = itr->first; ++itr; Unit high = itr->first; evaluateInterval_(outputContainer, interval_data<Unit>(low, high), beforeCount, afterCount); } //merge the bottom interval with the one below if they have the same count if(lowItr != scanData_.begin()){ typename ScanData::iterator belowLowItr = lowItr; --belowLowItr; if(belowLowItr->second == lowItr->second) { scanData_.erase(lowItr); } } //merge the top interval with the one above if they have the same count if(highItr != scanData_.begin()) { typename ScanData::iterator beforeHighItr = highItr; --beforeHighItr; if(beforeHighItr->second == highItr->second) { scanData_.erase(highItr); highItr = beforeHighItr; ++highItr; } } nextItr_ = highItr; } template <class T, typename Unit> template <class cT> inline void BooleanOp<T, Unit>::evaluateInterval_(cT& outputContainer, interval_data<Unit> ivl, T beforeCount, T afterCount) { bool before = (int)beforeCount > 0; bool after = (int)afterCount > 0; int value = (!before & after) - (before & !after); if(value) { outputContainer.insert(outputContainer.end(), std::pair<interval_data<Unit>, int>(ivl, value)); } } template <class T> inline BinaryCount<T>& BinaryCount<T>::operator=(const BinaryCount<T>& that) { counts_[0] = that.counts_[0]; counts_[1] = that.counts_[1]; return *this; } template <class T> inline bool BinaryCount<T>::operator==(const BinaryCount<T>& that) const { return counts_[0] == that.counts_[0] && counts_[1] == that.counts_[1]; } template <class T> inline BinaryCount<T>& BinaryCount<T>::operator+=(const BinaryCount<T>& that) { counts_[0] += that.counts_[0]; counts_[1] += that.counts_[1]; return *this; } template <class T> inline BinaryCount<T>& BinaryCount<T>::operator-=(const BinaryCount<T>& that) { counts_[0] += that.counts_[0]; counts_[1] += that.counts_[1]; return *this; } template <class T> inline BinaryCount<T> BinaryCount<T>::operator+(const BinaryCount<T>& that) const { BinaryCount retVal(*this); retVal += that; return retVal; } template <class T> inline BinaryCount<T> BinaryCount<T>::operator-(const BinaryCount<T>& that) const { BinaryCount retVal(*this); retVal -= that; return retVal; } template <class T> inline BinaryCount<T> BinaryCount<T>::operator-() const { return BinaryCount<T>() - *this; } template <class T, typename Unit, typename iterator_type_1, typename iterator_type_2> inline void applyBooleanBinaryOp(std::vector<std::pair<Unit, std::pair<Unit, int> > >& output, //const std::vector<std::pair<Unit, std::pair<Unit, int> > >& input1, //const std::vector<std::pair<Unit, std::pair<Unit, int> > >& input2, iterator_type_1 itr1, iterator_type_1 itr1_end, iterator_type_2 itr2, iterator_type_2 itr2_end, T defaultCount) { BooleanOp<T, Unit> boolean(defaultCount); //typename std::vector<std::pair<Unit, std::pair<Unit, int> > >::const_iterator itr1 = input1.begin(); //typename std::vector<std::pair<Unit, std::pair<Unit, int> > >::const_iterator itr2 = input2.begin(); std::vector<std::pair<interval_data<Unit>, int> > container; //output.reserve((std::max)(input1.size(), input2.size())); //consider eliminating dependecy on limits with bool flag for initial state Unit UnitMax = (std::numeric_limits<Unit>::max)(); Unit prevCoord = UnitMax; Unit prevPosition = UnitMax; T count(defaultCount); //define the starting point if(itr1 != itr1_end) { prevCoord = (*itr1).first; prevPosition = (*itr1).second.first; count[0] += (*itr1).second.second; } if(itr2 != itr2_end) { if((*itr2).first < prevCoord || ((*itr2).first == prevCoord && (*itr2).second.first < prevPosition)) { prevCoord = (*itr2).first; prevPosition = (*itr2).second.first; count = defaultCount; count[1] += (*itr2).second.second; ++itr2; } else if((*itr2).first == prevCoord && (*itr2).second.first == prevPosition) { count[1] += (*itr2).second.second; ++itr2; if(itr1 != itr1_end) ++itr1; } else { if(itr1 != itr1_end) ++itr1; } } else { if(itr1 != itr1_end) ++itr1; } while(itr1 != itr1_end || itr2 != itr2_end) { Unit curCoord = UnitMax; Unit curPosition = UnitMax; T curCount(defaultCount); if(itr1 != itr1_end) { curCoord = (*itr1).first; curPosition = (*itr1).second.first; curCount[0] += (*itr1).second.second; } if(itr2 != itr2_end) { if((*itr2).first < curCoord || ((*itr2).first == curCoord && (*itr2).second.first < curPosition)) { curCoord = (*itr2).first; curPosition = (*itr2).second.first; curCount = defaultCount; curCount[1] += (*itr2).second.second; ++itr2; } else if((*itr2).first == curCoord && (*itr2).second.first == curPosition) { curCount[1] += (*itr2).second.second; ++itr2; if(itr1 != itr1_end) ++itr1; } else { if(itr1 != itr1_end) ++itr1; } } else { ++itr1; } if(prevCoord != curCoord) { boolean.advanceScan(); prevCoord = curCoord; prevPosition = curPosition; count = curCount; continue; } if(curPosition != prevPosition && count != defaultCount) { interval_data<Unit> ivl(prevPosition, curPosition); container.clear(); boolean.processInterval(container, ivl, count); for(std::size_t i = 0; i < container.size(); ++i) { std::pair<interval_data<Unit>, int>& element = container[i]; if(!output.empty() && output.back().first == prevCoord && output.back().second.first == element.first.low() && output.back().second.second == element.second * -1) { output.pop_back(); } else { output.push_back(std::pair<Unit, std::pair<Unit, int> >(prevCoord, std::pair<Unit, int>(element.first.low(), element.second))); } output.push_back(std::pair<Unit, std::pair<Unit, int> >(prevCoord, std::pair<Unit, int>(element.first.high(), element.second * -1))); } } prevPosition = curPosition; count += curCount; } } template <class T, typename Unit> inline void applyBooleanBinaryOp(std::vector<std::pair<Unit, std::pair<Unit, int> > >& inputOutput, const std::vector<std::pair<Unit, std::pair<Unit, int> > >& input2, T defaultCount) { std::vector<std::pair<Unit, std::pair<Unit, int> > > output; applyBooleanBinaryOp(output, inputOutput, input2, defaultCount); if(output.size() < inputOutput.size() / 2) { inputOutput = std::vector<std::pair<Unit, std::pair<Unit, int> > >(); } else { inputOutput.clear(); } inputOutput.insert(inputOutput.end(), output.begin(), output.end()); } template <typename count_type = int> struct default_arg_workaround { template <typename Unit> static inline void applyBooleanOr(std::vector<std::pair<Unit, std::pair<Unit, int> > >& input) { BooleanOp<count_type, Unit> booleanOr; std::vector<std::pair<interval_data<Unit>, int> > container; std::vector<std::pair<Unit, std::pair<Unit, int> > > output; output.reserve(input.size()); //consider eliminating dependecy on limits with bool flag for initial state Unit UnitMax = (std::numeric_limits<Unit>::max)(); Unit prevPos = UnitMax; Unit prevY = UnitMax; int count = 0; for(typename std::vector<std::pair<Unit, std::pair<Unit, int> > >::iterator itr = input.begin(); itr != input.end(); ++itr) { Unit pos = (*itr).first; Unit y = (*itr).second.first; if(pos != prevPos) { booleanOr.advanceScan(); prevPos = pos; prevY = y; count = (*itr).second.second; continue; } if(y != prevY && count != 0) { interval_data<Unit> ivl(prevY, y); container.clear(); booleanOr.processInterval(container, ivl, count_type(count)); for(std::size_t i = 0; i < container.size(); ++i) { std::pair<interval_data<Unit>, int>& element = container[i]; if(!output.empty() && output.back().first == prevPos && output.back().second.first == element.first.low() && output.back().second.second == element.second * -1) { output.pop_back(); } else { output.push_back(std::pair<Unit, std::pair<Unit, int> >(prevPos, std::pair<Unit, int>(element.first.low(), element.second))); } output.push_back(std::pair<Unit, std::pair<Unit, int> >(prevPos, std::pair<Unit, int>(element.first.high(), element.second * -1))); } } prevY = y; count += (*itr).second.second; } if(output.size() < input.size() / 2) { input = std::vector<std::pair<Unit, std::pair<Unit, int> > >(); } else { input.clear(); } input.insert(input.end(), output.begin(), output.end()); } }; } } } #endif detail/iterator_compact_to_points.hpp 0000644 00000004350 15125572616 0014170 0 ustar 00 /* 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_ITERATOR_COMPACT_TO_POINTS_HPP #define BOOST_POLYGON_ITERATOR_COMPACT_TO_POINTS_HPP namespace boost { namespace polygon{ template <typename iterator_type, typename point_type> class iterator_compact_to_points { private: iterator_type iter_; iterator_type iter_end_; point_type pt_; typename point_traits<point_type>::coordinate_type firstX_; orientation_2d orient_; public: typedef std::forward_iterator_tag iterator_category; typedef point_type value_type; typedef std::ptrdiff_t difference_type; typedef const point_type* pointer; //immutable typedef const point_type& reference; //immutable inline iterator_compact_to_points() : iter_(), iter_end_(), pt_(), firstX_(), orient_() {} inline iterator_compact_to_points(iterator_type iter, iterator_type iter_end) : iter_(iter), iter_end_(iter_end), pt_(), firstX_(), orient_(HORIZONTAL) { if(iter_ != iter_end_) { firstX_ = *iter_; x(pt_, firstX_); ++iter_; if(iter_ != iter_end_) { y(pt_, *iter_); } } } //use bitwise copy and assign provided by the compiler inline iterator_compact_to_points& operator++() { iterator_type prev_iter = iter_; ++iter_; if(iter_ == iter_end_) { if(x(pt_) != firstX_) { iter_ = prev_iter; x(pt_, firstX_); } } else { set(pt_, orient_, *iter_); orient_.turn_90(); } return *this; } inline const iterator_compact_to_points operator++(int) { iterator_compact_to_points tmp(*this); ++(*this); return tmp; } inline bool operator==(const iterator_compact_to_points& that) const { if (iter_ == iter_end_) { return iter_ == that.iter_; } return (iter_ == that.iter_) && (x(pt_) == x(that.pt_)); } inline bool operator!=(const iterator_compact_to_points& that) const { if (iter_ == iter_end_) { return iter_ != that.iter_; } return (iter_ != that.iter_) || (x(pt_) != x(that.pt_)); } inline reference operator*() const { return pt_; } }; } } #endif detail/voronoi_robust_fpt.hpp 0000644 00000034644 15125572616 0012506 0 ustar 00 // Boost.Polygon library detail/voronoi_robust_fpt.hpp header file // Copyright Andrii Sydorchuk 2010-2012. // Distributed under 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) // See http://www.boost.org for updates, documentation, and revision history. #ifndef BOOST_POLYGON_DETAIL_VORONOI_ROBUST_FPT #define BOOST_POLYGON_DETAIL_VORONOI_ROBUST_FPT #include <algorithm> #include <cmath> // Geometry predicates with floating-point variables usually require // high-precision predicates to retrieve the correct result. // Epsilon robust predicates give the result within some epsilon relative // error, but are a lot faster than high-precision predicates. // To make algorithm robust and efficient epsilon robust predicates are // used at the first step. In case of the undefined result high-precision // arithmetic is used to produce required robustness. This approach // requires exact computation of epsilon intervals within which epsilon // robust predicates have undefined value. // There are two ways to measure an error of floating-point calculations: // relative error and ULPs (units in the last place). // Let EPS be machine epsilon, then next inequalities have place: // 1 EPS <= 1 ULP <= 2 EPS (1), 0.5 ULP <= 1 EPS <= 1 ULP (2). // ULPs are good for measuring rounding errors and comparing values. // Relative errors are good for computation of general relative // error of formulas or expressions. So to calculate epsilon // interval within which epsilon robust predicates have undefined result // next schema is used: // 1) Compute rounding errors of initial variables using ULPs; // 2) Transform ULPs to epsilons using upper bound of the (1); // 3) Compute relative error of the formula using epsilon arithmetic; // 4) Transform epsilon to ULPs using upper bound of the (2); // In case two values are inside undefined ULP range use high-precision // arithmetic to produce the correct result, else output the result. // Look at almost_equal function to see how two floating-point variables // are checked to fit in the ULP range. // If A has relative error of r(A) and B has relative error of r(B) then: // 1) r(A + B) <= max(r(A), r(B)), for A * B >= 0; // 2) r(A - B) <= B*r(A)+A*r(B)/(A-B), for A * B >= 0; // 2) r(A * B) <= r(A) + r(B); // 3) r(A / B) <= r(A) + r(B); // In addition rounding error should be added, that is always equal to // 0.5 ULP or at most 1 epsilon. As you might see from the above formulas // subtraction relative error may be extremely large, that's why // epsilon robust comparator class is used to store floating point values // and compute subtraction as the final step of the evaluation. // For further information about relative errors and ULPs try this link: // http://docs.sun.com/source/806-3568/ncg_goldberg.html namespace boost { namespace polygon { namespace detail { template <typename T> T get_sqrt(const T& that) { return (std::sqrt)(that); } template <typename T> bool is_pos(const T& that) { return that > 0; } template <typename T> bool is_neg(const T& that) { return that < 0; } template <typename T> bool is_zero(const T& that) { return that == 0; } template <typename _fpt> class robust_fpt { public: typedef _fpt floating_point_type; typedef _fpt relative_error_type; // Rounding error is at most 1 EPS. enum { ROUNDING_ERROR = 1 }; robust_fpt() : fpv_(0.0), re_(0.0) {} explicit robust_fpt(floating_point_type fpv) : fpv_(fpv), re_(0.0) {} robust_fpt(floating_point_type fpv, relative_error_type error) : fpv_(fpv), re_(error) {} floating_point_type fpv() const { return fpv_; } relative_error_type re() const { return re_; } relative_error_type ulp() const { return re_; } bool has_pos_value() const { return is_pos(fpv_); } bool has_neg_value() const { return is_neg(fpv_); } bool has_zero_value() const { return is_zero(fpv_); } robust_fpt operator-() const { return robust_fpt(-fpv_, re_); } robust_fpt& operator+=(const robust_fpt& that) { floating_point_type fpv = this->fpv_ + that.fpv_; if ((!is_neg(this->fpv_) && !is_neg(that.fpv_)) || (!is_pos(this->fpv_) && !is_pos(that.fpv_))) { this->re_ = (std::max)(this->re_, that.re_) + ROUNDING_ERROR; } else { floating_point_type temp = (this->fpv_ * this->re_ - that.fpv_ * that.re_) / fpv; if (is_neg(temp)) temp = -temp; this->re_ = temp + ROUNDING_ERROR; } this->fpv_ = fpv; return *this; } robust_fpt& operator-=(const robust_fpt& that) { floating_point_type fpv = this->fpv_ - that.fpv_; if ((!is_neg(this->fpv_) && !is_pos(that.fpv_)) || (!is_pos(this->fpv_) && !is_neg(that.fpv_))) { this->re_ = (std::max)(this->re_, that.re_) + ROUNDING_ERROR; } else { floating_point_type temp = (this->fpv_ * this->re_ + that.fpv_ * that.re_) / fpv; if (is_neg(temp)) temp = -temp; this->re_ = temp + ROUNDING_ERROR; } this->fpv_ = fpv; return *this; } robust_fpt& operator*=(const robust_fpt& that) { this->re_ += that.re_ + ROUNDING_ERROR; this->fpv_ *= that.fpv_; return *this; } robust_fpt& operator/=(const robust_fpt& that) { this->re_ += that.re_ + ROUNDING_ERROR; this->fpv_ /= that.fpv_; return *this; } robust_fpt operator+(const robust_fpt& that) const { floating_point_type fpv = this->fpv_ + that.fpv_; relative_error_type re; if ((!is_neg(this->fpv_) && !is_neg(that.fpv_)) || (!is_pos(this->fpv_) && !is_pos(that.fpv_))) { re = (std::max)(this->re_, that.re_) + ROUNDING_ERROR; } else { floating_point_type temp = (this->fpv_ * this->re_ - that.fpv_ * that.re_) / fpv; if (is_neg(temp)) temp = -temp; re = temp + ROUNDING_ERROR; } return robust_fpt(fpv, re); } robust_fpt operator-(const robust_fpt& that) const { floating_point_type fpv = this->fpv_ - that.fpv_; relative_error_type re; if ((!is_neg(this->fpv_) && !is_pos(that.fpv_)) || (!is_pos(this->fpv_) && !is_neg(that.fpv_))) { re = (std::max)(this->re_, that.re_) + ROUNDING_ERROR; } else { floating_point_type temp = (this->fpv_ * this->re_ + that.fpv_ * that.re_) / fpv; if (is_neg(temp)) temp = -temp; re = temp + ROUNDING_ERROR; } return robust_fpt(fpv, re); } robust_fpt operator*(const robust_fpt& that) const { floating_point_type fpv = this->fpv_ * that.fpv_; relative_error_type re = this->re_ + that.re_ + ROUNDING_ERROR; return robust_fpt(fpv, re); } robust_fpt operator/(const robust_fpt& that) const { floating_point_type fpv = this->fpv_ / that.fpv_; relative_error_type re = this->re_ + that.re_ + ROUNDING_ERROR; return robust_fpt(fpv, re); } robust_fpt sqrt() const { return robust_fpt(get_sqrt(fpv_), re_ * static_cast<relative_error_type>(0.5) + ROUNDING_ERROR); } private: floating_point_type fpv_; relative_error_type re_; }; template <typename T> robust_fpt<T> get_sqrt(const robust_fpt<T>& that) { return that.sqrt(); } template <typename T> bool is_pos(const robust_fpt<T>& that) { return that.has_pos_value(); } template <typename T> bool is_neg(const robust_fpt<T>& that) { return that.has_neg_value(); } template <typename T> bool is_zero(const robust_fpt<T>& that) { return that.has_zero_value(); } // robust_dif consists of two not negative values: value1 and value2. // The resulting expression is equal to the value1 - value2. // Subtraction of a positive value is equivalent to the addition to value2 // and subtraction of a negative value is equivalent to the addition to // value1. The structure implicitly avoids difference computation. template <typename T> class robust_dif { public: robust_dif() : positive_sum_(0), negative_sum_(0) {} explicit robust_dif(const T& value) : positive_sum_((value > 0)?value:0), negative_sum_((value < 0)?-value:0) {} robust_dif(const T& pos, const T& neg) : positive_sum_(pos), negative_sum_(neg) {} T dif() const { return positive_sum_ - negative_sum_; } T pos() const { return positive_sum_; } T neg() const { return negative_sum_; } robust_dif<T> operator-() const { return robust_dif(negative_sum_, positive_sum_); } robust_dif<T>& operator+=(const T& val) { if (!is_neg(val)) positive_sum_ += val; else negative_sum_ -= val; return *this; } robust_dif<T>& operator+=(const robust_dif<T>& that) { positive_sum_ += that.positive_sum_; negative_sum_ += that.negative_sum_; return *this; } robust_dif<T>& operator-=(const T& val) { if (!is_neg(val)) negative_sum_ += val; else positive_sum_ -= val; return *this; } robust_dif<T>& operator-=(const robust_dif<T>& that) { positive_sum_ += that.negative_sum_; negative_sum_ += that.positive_sum_; return *this; } robust_dif<T>& operator*=(const T& val) { if (!is_neg(val)) { positive_sum_ *= val; negative_sum_ *= val; } else { positive_sum_ *= -val; negative_sum_ *= -val; swap(); } return *this; } robust_dif<T>& operator*=(const robust_dif<T>& that) { T positive_sum = this->positive_sum_ * that.positive_sum_ + this->negative_sum_ * that.negative_sum_; T negative_sum = this->positive_sum_ * that.negative_sum_ + this->negative_sum_ * that.positive_sum_; positive_sum_ = positive_sum; negative_sum_ = negative_sum; return *this; } robust_dif<T>& operator/=(const T& val) { if (!is_neg(val)) { positive_sum_ /= val; negative_sum_ /= val; } else { positive_sum_ /= -val; negative_sum_ /= -val; swap(); } return *this; } private: void swap() { (std::swap)(positive_sum_, negative_sum_); } T positive_sum_; T negative_sum_; }; template<typename T> robust_dif<T> operator+(const robust_dif<T>& lhs, const robust_dif<T>& rhs) { return robust_dif<T>(lhs.pos() + rhs.pos(), lhs.neg() + rhs.neg()); } template<typename T> robust_dif<T> operator+(const robust_dif<T>& lhs, const T& rhs) { if (!is_neg(rhs)) { return robust_dif<T>(lhs.pos() + rhs, lhs.neg()); } else { return robust_dif<T>(lhs.pos(), lhs.neg() - rhs); } } template<typename T> robust_dif<T> operator+(const T& lhs, const robust_dif<T>& rhs) { if (!is_neg(lhs)) { return robust_dif<T>(lhs + rhs.pos(), rhs.neg()); } else { return robust_dif<T>(rhs.pos(), rhs.neg() - lhs); } } template<typename T> robust_dif<T> operator-(const robust_dif<T>& lhs, const robust_dif<T>& rhs) { return robust_dif<T>(lhs.pos() + rhs.neg(), lhs.neg() + rhs.pos()); } template<typename T> robust_dif<T> operator-(const robust_dif<T>& lhs, const T& rhs) { if (!is_neg(rhs)) { return robust_dif<T>(lhs.pos(), lhs.neg() + rhs); } else { return robust_dif<T>(lhs.pos() - rhs, lhs.neg()); } } template<typename T> robust_dif<T> operator-(const T& lhs, const robust_dif<T>& rhs) { if (!is_neg(lhs)) { return robust_dif<T>(lhs + rhs.neg(), rhs.pos()); } else { return robust_dif<T>(rhs.neg(), rhs.pos() - lhs); } } template<typename T> robust_dif<T> operator*(const robust_dif<T>& lhs, const robust_dif<T>& rhs) { T res_pos = lhs.pos() * rhs.pos() + lhs.neg() * rhs.neg(); T res_neg = lhs.pos() * rhs.neg() + lhs.neg() * rhs.pos(); return robust_dif<T>(res_pos, res_neg); } template<typename T> robust_dif<T> operator*(const robust_dif<T>& lhs, const T& val) { if (!is_neg(val)) { return robust_dif<T>(lhs.pos() * val, lhs.neg() * val); } else { return robust_dif<T>(-lhs.neg() * val, -lhs.pos() * val); } } template<typename T> robust_dif<T> operator*(const T& val, const robust_dif<T>& rhs) { if (!is_neg(val)) { return robust_dif<T>(val * rhs.pos(), val * rhs.neg()); } else { return robust_dif<T>(-val * rhs.neg(), -val * rhs.pos()); } } template<typename T> robust_dif<T> operator/(const robust_dif<T>& lhs, const T& val) { if (!is_neg(val)) { return robust_dif<T>(lhs.pos() / val, lhs.neg() / val); } else { return robust_dif<T>(-lhs.neg() / val, -lhs.pos() / val); } } // Used to compute expressions that operate with sqrts with predefined // relative error. Evaluates expressions of the next type: // sum(i = 1 .. n)(A[i] * sqrt(B[i])), 1 <= n <= 4. template <typename _int, typename _fpt, typename _converter> class robust_sqrt_expr { public: enum MAX_RELATIVE_ERROR { MAX_RELATIVE_ERROR_EVAL1 = 4, MAX_RELATIVE_ERROR_EVAL2 = 7, MAX_RELATIVE_ERROR_EVAL3 = 16, MAX_RELATIVE_ERROR_EVAL4 = 25 }; // Evaluates expression (re = 4 EPS): // A[0] * sqrt(B[0]). _fpt eval1(_int* A, _int* B) { _fpt a = convert(A[0]); _fpt b = convert(B[0]); return a * get_sqrt(b); } // Evaluates expression (re = 7 EPS): // A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]). _fpt eval2(_int* A, _int* B) { _fpt a = eval1(A, B); _fpt b = eval1(A + 1, B + 1); if ((!is_neg(a) && !is_neg(b)) || (!is_pos(a) && !is_pos(b))) return a + b; return convert(A[0] * A[0] * B[0] - A[1] * A[1] * B[1]) / (a - b); } // Evaluates expression (re = 16 EPS): // A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) + A[2] * sqrt(B[2]). _fpt eval3(_int* A, _int* B) { _fpt a = eval2(A, B); _fpt b = eval1(A + 2, B + 2); if ((!is_neg(a) && !is_neg(b)) || (!is_pos(a) && !is_pos(b))) return a + b; tA[3] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] - A[2] * A[2] * B[2]; tB[3] = 1; tA[4] = A[0] * A[1] * 2; tB[4] = B[0] * B[1]; return eval2(tA + 3, tB + 3) / (a - b); } // Evaluates expression (re = 25 EPS): // A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) + // A[2] * sqrt(B[2]) + A[3] * sqrt(B[3]). _fpt eval4(_int* A, _int* B) { _fpt a = eval2(A, B); _fpt b = eval2(A + 2, B + 2); if ((!is_neg(a) && !is_neg(b)) || (!is_pos(a) && !is_pos(b))) return a + b; tA[0] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] - A[2] * A[2] * B[2] - A[3] * A[3] * B[3]; tB[0] = 1; tA[1] = A[0] * A[1] * 2; tB[1] = B[0] * B[1]; tA[2] = A[2] * A[3] * -2; tB[2] = B[2] * B[3]; return eval3(tA, tB) / (a - b); } private: _int tA[5]; _int tB[5]; _converter convert; }; } // detail } // polygon } // boost #endif // BOOST_POLYGON_DETAIL_VORONOI_ROBUST_FPT detail/polygon_45_touch.hpp 0000644 00000022104 15125572616 0011731 0 ustar 00 /* 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_45_TOUCH_HPP #define BOOST_POLYGON_POLYGON_45_TOUCH_HPP namespace boost { namespace polygon{ template <typename Unit> struct polygon_45_touch { typedef point_data<Unit> Point; typedef typename coordinate_traits<Unit>::manhattan_area_type LongUnit; template <typename property_map> static inline void merge_property_maps(property_map& mp, const property_map& mp2, bool subtract = false) { property_map newmp; newmp.reserve(mp.size() + mp2.size()); std::size_t i = 0; std::size_t j = 0; while(i != mp.size() && j != mp2.size()) { if(mp[i].first < mp2[j].first) { newmp.push_back(mp[i]); ++i; } else if(mp[i].first > mp2[j].first) { newmp.push_back(mp2[j]); if(subtract) newmp.back().second *= -1; ++j; } else { int count = mp[i].second; if(subtract) count -= mp2[j].second; else count += mp2[j].second; if(count) { newmp.push_back(mp[i]); newmp.back().second = count; } ++i; ++j; } } while(i != mp.size()) { newmp.push_back(mp[i]); ++i; } while(j != mp2.size()) { newmp.push_back(mp2[j]); if(subtract) newmp.back().second *= -1; ++j; } mp.swap(newmp); } class CountTouch { public: inline CountTouch() : counts() {} //inline CountTouch(int count) { counts[0] = counts[1] = count; } //inline CountTouch(int count1, int count2) { counts[0] = count1; counts[1] = count2; } inline CountTouch(const CountTouch& count) : counts(count.counts) {} inline bool operator==(const CountTouch& count) const { return counts == count.counts; } inline bool operator!=(const CountTouch& count) const { return !((*this) == count); } //inline CountTouch& operator=(int count) { counts[0] = counts[1] = count; return *this; } inline CountTouch& operator=(const CountTouch& count) { counts = count.counts; return *this; } inline int& operator[](int index) { std::vector<std::pair<int, int> >::iterator itr = std::lower_bound(counts.begin(), counts.end(), std::make_pair(index, int(0))); if(itr != counts.end() && itr->first == index) { return itr->second; } itr = counts.insert(itr, std::make_pair(index, int(0))); return itr->second; } // inline int operator[](int index) const { // std::vector<std::pair<int, int> >::const_iterator itr = counts.begin(); // for( ; itr != counts.end() && itr->first <= index; ++itr) { // if(itr->first == index) { // return itr->second; // } // } // return 0; // } inline CountTouch& operator+=(const CountTouch& count){ merge_property_maps(counts, count.counts, false); return *this; } inline CountTouch& operator-=(const CountTouch& count){ merge_property_maps(counts, count.counts, true); return *this; } inline CountTouch operator+(const CountTouch& count) const { return CountTouch(*this)+=count; } inline CountTouch operator-(const CountTouch& count) const { return CountTouch(*this)-=count; } inline CountTouch invert() const { CountTouch retval; retval -= *this; return retval; } std::vector<std::pair<int, int> > counts; }; typedef std::pair<std::pair<Unit, std::map<Unit, std::set<int> > >, std::map<int, std::set<int> > > map_graph_o; typedef std::pair<std::pair<Unit, std::map<Unit, std::set<int> > >, std::vector<std::set<int> > > vector_graph_o; template <typename cT> static void process_previous_x(cT& output) { std::map<Unit, std::set<int> >& y_prop_map = output.first.second; for(typename std::map<Unit, std::set<int> >::iterator itr = y_prop_map.begin(); itr != y_prop_map.end(); ++itr) { for(std::set<int>::iterator inner_itr = itr->second.begin(); inner_itr != itr->second.end(); ++inner_itr) { std::set<int>& output_edges = (*(output.second))[*inner_itr]; std::set<int>::iterator inner_inner_itr = inner_itr; ++inner_inner_itr; for( ; inner_inner_itr != itr->second.end(); ++inner_inner_itr) { output_edges.insert(output_edges.end(), *inner_inner_itr); std::set<int>& output_edges_2 = (*(output.second))[*inner_inner_itr]; output_edges_2.insert(output_edges_2.end(), *inner_itr); } } } y_prop_map.clear(); } struct touch_45_output_functor { template <typename cT> void operator()(cT& output, const CountTouch& count1, const CountTouch& count2, const Point& pt, int , direction_1d ) { Unit& x = output.first.first; std::map<Unit, std::set<int> >& y_prop_map = output.first.second; if(pt.x() != x) process_previous_x(output); x = pt.x(); std::set<int>& output_set = y_prop_map[pt.y()]; for(std::vector<std::pair<int, int> >::const_iterator itr1 = count1.counts.begin(); itr1 != count1.counts.end(); ++itr1) { if(itr1->second > 0) { output_set.insert(output_set.end(), itr1->first); } } for(std::vector<std::pair<int, int> >::const_iterator itr2 = count2.counts.begin(); itr2 != count2.counts.end(); ++itr2) { if(itr2->second > 0) { output_set.insert(output_set.end(), itr2->first); } } } }; typedef typename std::pair<Point, typename boolean_op_45<Unit>::template Scan45CountT<CountTouch> > Vertex45Compact; typedef std::vector<Vertex45Compact> TouchSetData; struct lessVertex45Compact { bool operator()(const Vertex45Compact& l, const Vertex45Compact& r) { return l.first < r.first; } }; // template <typename TSD> // static void print_tsd(TSD& tsd) { // for(std::size_t i = 0; i < tsd.size(); ++i) { // std::cout << tsd[i].first << ": "; // for(unsigned int r = 0; r < 4; ++r) { // std::cout << r << " { "; // for(std::vector<std::pair<int, int> >::iterator itr = tsd[i].second[r].counts.begin(); // itr != tsd[i].second[r].counts.end(); ++itr) { // std::cout << itr->first << "," << itr->second << " "; // } std::cout << "} "; // } // } std::cout << std::endl; // } // template <typename T> // static void print_scanline(T& t) { // for(typename T::iterator itr = t.begin(); itr != t.end(); ++itr) { // std::cout << itr->x << "," << itr->y << " " << itr->rise << " "; // for(std::vector<std::pair<int, int> >::iterator itr2 = itr->count.counts.begin(); // itr2 != itr->count.counts.end(); ++itr2) { // std::cout << itr2->first << ":" << itr2->second << " "; // } std::cout << std::endl; // } // } template <typename graph_type> static void performTouch(graph_type& graph, TouchSetData& tsd) { polygon_sort(tsd.begin(), tsd.end(), lessVertex45Compact()); typedef std::vector<std::pair<Point, typename boolean_op_45<Unit>::template Scan45CountT<CountTouch> > > TSD; TSD tsd_; tsd_.reserve(tsd.size()); for(typename TouchSetData::iterator itr = tsd.begin(); itr != tsd.end(); ) { typename TouchSetData::iterator itr2 = itr; ++itr2; for(; itr2 != tsd.end() && itr2->first == itr->first; ++itr2) { (itr->second) += (itr2->second); //accumulate } tsd_.push_back(std::make_pair(itr->first, itr->second)); itr = itr2; } std::pair<std::pair<Unit, std::map<Unit, std::set<int> > >, graph_type*> output (std::make_pair(std::make_pair((std::numeric_limits<Unit>::max)(), std::map<Unit, std::set<int> >()), &graph)); typename boolean_op_45<Unit>::template Scan45<CountTouch, touch_45_output_functor> scanline; for(typename TSD::iterator itr = tsd_.begin(); itr != tsd_.end(); ) { typename TSD::iterator itr2 = itr; ++itr2; while(itr2 != tsd_.end() && itr2->first.x() == itr->first.x()) { ++itr2; } scanline.scan(output, itr, itr2); itr = itr2; } process_previous_x(output); } template <typename iT> static void populateTouchSetData(TouchSetData& tsd, iT begin, iT end, int nodeCount) { for( ; begin != end; ++begin) { Vertex45Compact vertex; vertex.first = typename Vertex45Compact::first_type(begin->pt.x() * 2, begin->pt.y() * 2); tsd.push_back(vertex); for(unsigned int i = 0; i < 4; ++i) { if(begin->count[i]) { tsd.back().second[i][nodeCount] += begin->count[i]; } } } } }; } } #endif detail/voronoi_predicates.hpp 0000644 00000172435 15125572616 0012443 0 ustar 00 // Boost.Polygon library detail/voronoi_predicates.hpp header file // Copyright Andrii Sydorchuk 2010-2012. // Distributed under 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) // See http://www.boost.org for updates, documentation, and revision history. #ifndef BOOST_POLYGON_DETAIL_VORONOI_PREDICATES #define BOOST_POLYGON_DETAIL_VORONOI_PREDICATES #include <utility> #include "voronoi_robust_fpt.hpp" namespace boost { namespace polygon { namespace detail { // Predicate utilities. Operates with the coordinate types that could // be converted to the 32-bit signed integer without precision loss. template <typename CTYPE_TRAITS> class voronoi_predicates { public: typedef typename CTYPE_TRAITS::int_type int_type; typedef typename CTYPE_TRAITS::int_x2_type int_x2_type; typedef typename CTYPE_TRAITS::uint_x2_type uint_x2_type; typedef typename CTYPE_TRAITS::big_int_type big_int_type; typedef typename CTYPE_TRAITS::fpt_type fpt_type; typedef typename CTYPE_TRAITS::efpt_type efpt_type; typedef typename CTYPE_TRAITS::ulp_cmp_type ulp_cmp_type; typedef typename CTYPE_TRAITS::to_fpt_converter_type to_fpt_converter; typedef typename CTYPE_TRAITS::to_efpt_converter_type to_efpt_converter; enum { ULPS = 64, ULPSx2 = 128 }; template <typename Point> static bool is_vertical(const Point& point1, const Point& point2) { return point1.x() == point2.x(); } template <typename Site> static bool is_vertical(const Site& site) { return is_vertical(site.point0(), site.point1()); } // Compute robust cross_product: a1 * b2 - b1 * a2. // It was mathematically proven that the result is correct // with epsilon relative error equal to 1EPS. static fpt_type robust_cross_product(int_x2_type a1_, int_x2_type b1_, int_x2_type a2_, int_x2_type b2_) { static to_fpt_converter to_fpt; uint_x2_type a1 = static_cast<uint_x2_type>(is_neg(a1_) ? -a1_ : a1_); uint_x2_type b1 = static_cast<uint_x2_type>(is_neg(b1_) ? -b1_ : b1_); uint_x2_type a2 = static_cast<uint_x2_type>(is_neg(a2_) ? -a2_ : a2_); uint_x2_type b2 = static_cast<uint_x2_type>(is_neg(b2_) ? -b2_ : b2_); uint_x2_type l = a1 * b2; uint_x2_type r = b1 * a2; if (is_neg(a1_) ^ is_neg(b2_)) { if (is_neg(a2_) ^ is_neg(b1_)) return (l > r) ? -to_fpt(l - r) : to_fpt(r - l); else return -to_fpt(l + r); } else { if (is_neg(a2_) ^ is_neg(b1_)) return to_fpt(l + r); else return (l < r) ? -to_fpt(r - l) : to_fpt(l - r); } } struct orientation_test { public: // Represents orientation test result. enum Orientation { RIGHT = -1, COLLINEAR = 0, LEFT = 1 }; // Value is a determinant of two vectors (e.g. x1 * y2 - x2 * y1). // Return orientation based on the sign of the determinant. template <typename T> static Orientation eval(T value) { if (is_zero(value)) return COLLINEAR; return (is_neg(value)) ? RIGHT : LEFT; } static Orientation eval(int_x2_type dif_x1_, int_x2_type dif_y1_, int_x2_type dif_x2_, int_x2_type dif_y2_) { return eval(robust_cross_product(dif_x1_, dif_y1_, dif_x2_, dif_y2_)); } template <typename Point> static Orientation eval(const Point& point1, const Point& point2, const Point& point3) { int_x2_type dx1 = static_cast<int_x2_type>(point1.x()) - static_cast<int_x2_type>(point2.x()); int_x2_type dx2 = static_cast<int_x2_type>(point2.x()) - static_cast<int_x2_type>(point3.x()); int_x2_type dy1 = static_cast<int_x2_type>(point1.y()) - static_cast<int_x2_type>(point2.y()); int_x2_type dy2 = static_cast<int_x2_type>(point2.y()) - static_cast<int_x2_type>(point3.y()); return eval(robust_cross_product(dx1, dy1, dx2, dy2)); } }; typedef orientation_test ot; template <typename Point> class point_comparison_predicate { public: typedef Point point_type; bool operator()(const point_type& lhs, const point_type& rhs) const { if (lhs.x() == rhs.x()) return lhs.y() < rhs.y(); return lhs.x() < rhs.x(); } }; template <typename Site, typename Circle> class event_comparison_predicate { public: typedef Site site_type; typedef Circle circle_type; bool operator()(const site_type& lhs, const site_type& rhs) const { if (lhs.x0() != rhs.x0()) return lhs.x0() < rhs.x0(); if (!lhs.is_segment()) { if (!rhs.is_segment()) return lhs.y0() < rhs.y0(); if (is_vertical(rhs)) return lhs.y0() <= rhs.y0(); return true; } else { if (is_vertical(rhs)) { if (is_vertical(lhs)) return lhs.y0() < rhs.y0(); return false; } if (is_vertical(lhs)) return true; if (lhs.y0() != rhs.y0()) return lhs.y0() < rhs.y0(); return ot::eval(lhs.point1(), lhs.point0(), rhs.point1()) == ot::LEFT; } } bool operator()(const site_type& lhs, const circle_type& rhs) const { typename ulp_cmp_type::Result xCmp = ulp_cmp(to_fpt(lhs.x0()), to_fpt(rhs.lower_x()), ULPS); return xCmp == ulp_cmp_type::LESS; } bool operator()(const circle_type& lhs, const site_type& rhs) const { typename ulp_cmp_type::Result xCmp = ulp_cmp(to_fpt(lhs.lower_x()), to_fpt(rhs.x0()), ULPS); return xCmp == ulp_cmp_type::LESS; } bool operator()(const circle_type& lhs, const circle_type& rhs) const { if (lhs.lower_x() != rhs.lower_x()) { return lhs.lower_x() < rhs.lower_x(); } return lhs.y() < rhs.y(); } private: ulp_cmp_type ulp_cmp; to_fpt_converter to_fpt; }; template <typename Site> class distance_predicate { public: typedef Site site_type; typedef typename site_type::point_type point_type; // Returns true if a horizontal line going through a new site intersects // right arc at first, else returns false. If horizontal line goes // through intersection point of the given two arcs returns false also. bool operator()(const site_type& left_site, const site_type& right_site, const point_type& new_point) const { if (!left_site.is_segment()) { if (!right_site.is_segment()) { return pp(left_site, right_site, new_point); } else { return ps(left_site, right_site, new_point, false); } } else { if (!right_site.is_segment()) { return ps(right_site, left_site, new_point, true); } else { return ss(left_site, right_site, new_point); } } } private: // Represents the result of the epsilon robust predicate. If the // result is undefined some further processing is usually required. enum kPredicateResult { LESS = -1, UNDEFINED = 0, MORE = 1 }; // Robust predicate, avoids using high-precision libraries. // Returns true if a horizontal line going through the new point site // intersects right arc at first, else returns false. If horizontal line // goes through intersection point of the given two arcs returns false. bool pp(const site_type& left_site, const site_type& right_site, const point_type& new_point) const { const point_type& left_point = left_site.point0(); const point_type& right_point = right_site.point0(); if (left_point.x() > right_point.x()) { if (new_point.y() <= left_point.y()) return false; } else if (left_point.x() < right_point.x()) { if (new_point.y() >= right_point.y()) return true; } else { return static_cast<int_x2_type>(left_point.y()) + static_cast<int_x2_type>(right_point.y()) < static_cast<int_x2_type>(new_point.y()) * 2; } fpt_type dist1 = find_distance_to_point_arc(left_site, new_point); fpt_type dist2 = find_distance_to_point_arc(right_site, new_point); // The undefined ulp range is equal to 3EPS + 3EPS <= 6ULP. return dist1 < dist2; } bool ps(const site_type& left_site, const site_type& right_site, const point_type& new_point, bool reverse_order) const { kPredicateResult fast_res = fast_ps( left_site, right_site, new_point, reverse_order); if (fast_res != UNDEFINED) { return fast_res == LESS; } fpt_type dist1 = find_distance_to_point_arc(left_site, new_point); fpt_type dist2 = find_distance_to_segment_arc(right_site, new_point); // The undefined ulp range is equal to 3EPS + 7EPS <= 10ULP. return reverse_order ^ (dist1 < dist2); } bool ss(const site_type& left_site, const site_type& right_site, const point_type& new_point) const { // Handle temporary segment sites. if (left_site.sorted_index() == right_site.sorted_index()) { return ot::eval( left_site.point0(), left_site.point1(), new_point) == ot::LEFT; } fpt_type dist1 = find_distance_to_segment_arc(left_site, new_point); fpt_type dist2 = find_distance_to_segment_arc(right_site, new_point); // The undefined ulp range is equal to 7EPS + 7EPS <= 14ULP. return dist1 < dist2; } fpt_type find_distance_to_point_arc( const site_type& site, const point_type& point) const { fpt_type dx = to_fpt(site.x()) - to_fpt(point.x()); fpt_type dy = to_fpt(site.y()) - to_fpt(point.y()); // The relative error is at most 3EPS. return (dx * dx + dy * dy) / (to_fpt(2.0) * dx); } fpt_type find_distance_to_segment_arc( const site_type& site, const point_type& point) const { if (is_vertical(site)) { return (to_fpt(site.x()) - to_fpt(point.x())) * to_fpt(0.5); } else { const point_type& segment0 = site.point0(); const point_type& segment1 = site.point1(); fpt_type a1 = to_fpt(segment1.x()) - to_fpt(segment0.x()); fpt_type b1 = to_fpt(segment1.y()) - to_fpt(segment0.y()); fpt_type k = get_sqrt(a1 * a1 + b1 * b1); // Avoid subtraction while computing k. if (!is_neg(b1)) { k = to_fpt(1.0) / (b1 + k); } else { k = (k - b1) / (a1 * a1); } // The relative error is at most 7EPS. return k * robust_cross_product( static_cast<int_x2_type>(segment1.x()) - static_cast<int_x2_type>(segment0.x()), static_cast<int_x2_type>(segment1.y()) - static_cast<int_x2_type>(segment0.y()), static_cast<int_x2_type>(point.x()) - static_cast<int_x2_type>(segment0.x()), static_cast<int_x2_type>(point.y()) - static_cast<int_x2_type>(segment0.y())); } } kPredicateResult fast_ps( const site_type& left_site, const site_type& right_site, const point_type& new_point, bool reverse_order) const { const point_type& site_point = left_site.point0(); const point_type& segment_start = right_site.point0(); const point_type& segment_end = right_site.point1(); if (ot::eval(segment_start, segment_end, new_point) != ot::RIGHT) return (!right_site.is_inverse()) ? LESS : MORE; fpt_type dif_x = to_fpt(new_point.x()) - to_fpt(site_point.x()); fpt_type dif_y = to_fpt(new_point.y()) - to_fpt(site_point.y()); fpt_type a = to_fpt(segment_end.x()) - to_fpt(segment_start.x()); fpt_type b = to_fpt(segment_end.y()) - to_fpt(segment_start.y()); if (is_vertical(right_site)) { if (new_point.y() < site_point.y() && !reverse_order) return MORE; else if (new_point.y() > site_point.y() && reverse_order) return LESS; return UNDEFINED; } else { typename ot::Orientation orientation = ot::eval( static_cast<int_x2_type>(segment_end.x()) - static_cast<int_x2_type>(segment_start.x()), static_cast<int_x2_type>(segment_end.y()) - static_cast<int_x2_type>(segment_start.y()), static_cast<int_x2_type>(new_point.x()) - static_cast<int_x2_type>(site_point.x()), static_cast<int_x2_type>(new_point.y()) - static_cast<int_x2_type>(site_point.y())); if (orientation == ot::LEFT) { if (!right_site.is_inverse()) return reverse_order ? LESS : UNDEFINED; return reverse_order ? UNDEFINED : MORE; } } fpt_type fast_left_expr = a * (dif_y + dif_x) * (dif_y - dif_x); fpt_type fast_right_expr = (to_fpt(2.0) * b) * dif_x * dif_y; typename ulp_cmp_type::Result expr_cmp = ulp_cmp(fast_left_expr, fast_right_expr, 4); if (expr_cmp != ulp_cmp_type::EQUAL) { if ((expr_cmp == ulp_cmp_type::MORE) ^ reverse_order) return reverse_order ? LESS : MORE; return UNDEFINED; } return UNDEFINED; } private: ulp_cmp_type ulp_cmp; to_fpt_converter to_fpt; }; template <typename Node> class node_comparison_predicate { public: typedef Node node_type; typedef typename Node::site_type site_type; typedef typename site_type::point_type point_type; typedef typename point_type::coordinate_type coordinate_type; typedef point_comparison_predicate<point_type> point_comparison_type; typedef distance_predicate<site_type> distance_predicate_type; // Compares nodes in the balanced binary search tree. Nodes are // compared based on the y coordinates of the arcs intersection points. // Nodes with less y coordinate of the intersection point go first. // Comparison is only called during the new site events processing. // That's why one of the nodes will always lie on the sweepline and may // be represented as a straight horizontal line. bool operator() (const node_type& node1, const node_type& node2) const { // Get x coordinate of the rightmost site from both nodes. const site_type& site1 = get_comparison_site(node1); const site_type& site2 = get_comparison_site(node2); const point_type& point1 = get_comparison_point(site1); const point_type& point2 = get_comparison_point(site2); if (point1.x() < point2.x()) { // The second node contains a new site. return distance_predicate_( node1.left_site(), node1.right_site(), point2); } else if (point1.x() > point2.x()) { // The first node contains a new site. return !distance_predicate_( node2.left_site(), node2.right_site(), point1); } else { // This checks were evaluated experimentally. if (site1.sorted_index() == site2.sorted_index()) { // Both nodes are new (inserted during same site event processing). return get_comparison_y(node1) < get_comparison_y(node2); } else if (site1.sorted_index() < site2.sorted_index()) { std::pair<coordinate_type, int> y1 = get_comparison_y(node1, false); std::pair<coordinate_type, int> y2 = get_comparison_y(node2, true); if (y1.first != y2.first) return y1.first < y2.first; return (!site1.is_segment()) ? (y1.second < 0) : false; } else { std::pair<coordinate_type, int> y1 = get_comparison_y(node1, true); std::pair<coordinate_type, int> y2 = get_comparison_y(node2, false); if (y1.first != y2.first) return y1.first < y2.first; return (!site2.is_segment()) ? (y2.second > 0) : true; } } } private: // Get the newer site. const site_type& get_comparison_site(const node_type& node) const { if (node.left_site().sorted_index() > node.right_site().sorted_index()) { return node.left_site(); } return node.right_site(); } const point_type& get_comparison_point(const site_type& site) const { return point_comparison_(site.point0(), site.point1()) ? site.point0() : site.point1(); } // Get comparison pair: y coordinate and direction of the newer site. std::pair<coordinate_type, int> get_comparison_y( const node_type& node, bool is_new_node = true) const { if (node.left_site().sorted_index() == node.right_site().sorted_index()) { return std::make_pair(node.left_site().y0(), 0); } if (node.left_site().sorted_index() > node.right_site().sorted_index()) { if (!is_new_node && node.left_site().is_segment() && is_vertical(node.left_site())) { return std::make_pair(node.left_site().y0(), 1); } return std::make_pair(node.left_site().y1(), 1); } return std::make_pair(node.right_site().y0(), -1); } point_comparison_type point_comparison_; distance_predicate_type distance_predicate_; }; template <typename Site> class circle_existence_predicate { public: typedef typename Site::point_type point_type; typedef Site site_type; bool ppp(const site_type& site1, const site_type& site2, const site_type& site3) const { return ot::eval(site1.point0(), site2.point0(), site3.point0()) == ot::RIGHT; } bool pps(const site_type& site1, const site_type& site2, const site_type& site3, int segment_index) const { if (segment_index != 2) { typename ot::Orientation orient1 = ot::eval( site1.point0(), site2.point0(), site3.point0()); typename ot::Orientation orient2 = ot::eval( site1.point0(), site2.point0(), site3.point1()); if (segment_index == 1 && site1.x0() >= site2.x0()) { if (orient1 != ot::RIGHT) return false; } else if (segment_index == 3 && site2.x0() >= site1.x0()) { if (orient2 != ot::RIGHT) return false; } else if (orient1 != ot::RIGHT && orient2 != ot::RIGHT) { return false; } } else { return (site3.point0() != site1.point0()) || (site3.point1() != site2.point0()); } return true; } bool pss(const site_type& site1, const site_type& site2, const site_type& site3, int point_index) const { if (site2.sorted_index() == site3.sorted_index()) { return false; } if (point_index == 2) { if (!site2.is_inverse() && site3.is_inverse()) return false; if (site2.is_inverse() == site3.is_inverse() && ot::eval(site2.point0(), site1.point0(), site3.point1()) != ot::RIGHT) return false; } return true; } bool sss(const site_type& site1, const site_type& site2, const site_type& site3) const { return (site1.sorted_index() != site2.sorted_index()) && (site2.sorted_index() != site3.sorted_index()); } }; template <typename Site, typename Circle> class mp_circle_formation_functor { public: typedef typename Site::point_type point_type; typedef Site site_type; typedef Circle circle_type; typedef robust_sqrt_expr<big_int_type, efpt_type, to_efpt_converter> robust_sqrt_expr_type; void ppp(const site_type& site1, const site_type& site2, const site_type& site3, circle_type& circle, bool recompute_c_x = true, bool recompute_c_y = true, bool recompute_lower_x = true) { big_int_type dif_x[3], dif_y[3], sum_x[2], sum_y[2]; dif_x[0] = static_cast<int_x2_type>(site1.x()) - static_cast<int_x2_type>(site2.x()); dif_x[1] = static_cast<int_x2_type>(site2.x()) - static_cast<int_x2_type>(site3.x()); dif_x[2] = static_cast<int_x2_type>(site1.x()) - static_cast<int_x2_type>(site3.x()); dif_y[0] = static_cast<int_x2_type>(site1.y()) - static_cast<int_x2_type>(site2.y()); dif_y[1] = static_cast<int_x2_type>(site2.y()) - static_cast<int_x2_type>(site3.y()); dif_y[2] = static_cast<int_x2_type>(site1.y()) - static_cast<int_x2_type>(site3.y()); sum_x[0] = static_cast<int_x2_type>(site1.x()) + static_cast<int_x2_type>(site2.x()); sum_x[1] = static_cast<int_x2_type>(site2.x()) + static_cast<int_x2_type>(site3.x()); sum_y[0] = static_cast<int_x2_type>(site1.y()) + static_cast<int_x2_type>(site2.y()); sum_y[1] = static_cast<int_x2_type>(site2.y()) + static_cast<int_x2_type>(site3.y()); fpt_type inv_denom = to_fpt(0.5) / to_fpt(static_cast<big_int_type>( dif_x[0] * dif_y[1] - dif_x[1] * dif_y[0])); big_int_type numer1 = dif_x[0] * sum_x[0] + dif_y[0] * sum_y[0]; big_int_type numer2 = dif_x[1] * sum_x[1] + dif_y[1] * sum_y[1]; if (recompute_c_x || recompute_lower_x) { big_int_type c_x = numer1 * dif_y[1] - numer2 * dif_y[0]; circle.x(to_fpt(c_x) * inv_denom); if (recompute_lower_x) { // Evaluate radius of the circle. big_int_type sqr_r = (dif_x[0] * dif_x[0] + dif_y[0] * dif_y[0]) * (dif_x[1] * dif_x[1] + dif_y[1] * dif_y[1]) * (dif_x[2] * dif_x[2] + dif_y[2] * dif_y[2]); fpt_type r = get_sqrt(to_fpt(sqr_r)); // If c_x >= 0 then lower_x = c_x + r, // else lower_x = (c_x * c_x - r * r) / (c_x - r). // To guarantee epsilon relative error. if (!is_neg(circle.x())) { if (!is_neg(inv_denom)) { circle.lower_x(circle.x() + r * inv_denom); } else { circle.lower_x(circle.x() - r * inv_denom); } } else { big_int_type numer = c_x * c_x - sqr_r; fpt_type lower_x = to_fpt(numer) * inv_denom / (to_fpt(c_x) + r); circle.lower_x(lower_x); } } } if (recompute_c_y) { big_int_type c_y = numer2 * dif_x[0] - numer1 * dif_x[1]; circle.y(to_fpt(c_y) * inv_denom); } } // Recompute parameters of the circle event using high-precision library. void pps(const site_type& site1, const site_type& site2, const site_type& site3, int segment_index, circle_type& c_event, bool recompute_c_x = true, bool recompute_c_y = true, bool recompute_lower_x = true) { big_int_type cA[4], cB[4]; big_int_type line_a = static_cast<int_x2_type>(site3.y1()) - static_cast<int_x2_type>(site3.y0()); big_int_type line_b = static_cast<int_x2_type>(site3.x0()) - static_cast<int_x2_type>(site3.x1()); big_int_type segm_len = line_a * line_a + line_b * line_b; big_int_type vec_x = static_cast<int_x2_type>(site2.y()) - static_cast<int_x2_type>(site1.y()); big_int_type vec_y = static_cast<int_x2_type>(site1.x()) - static_cast<int_x2_type>(site2.x()); big_int_type sum_x = static_cast<int_x2_type>(site1.x()) + static_cast<int_x2_type>(site2.x()); big_int_type sum_y = static_cast<int_x2_type>(site1.y()) + static_cast<int_x2_type>(site2.y()); big_int_type teta = line_a * vec_x + line_b * vec_y; big_int_type denom = vec_x * line_b - vec_y * line_a; big_int_type dif0 = static_cast<int_x2_type>(site3.y1()) - static_cast<int_x2_type>(site1.y()); big_int_type dif1 = static_cast<int_x2_type>(site1.x()) - static_cast<int_x2_type>(site3.x1()); big_int_type A = line_a * dif1 - line_b * dif0; dif0 = static_cast<int_x2_type>(site3.y1()) - static_cast<int_x2_type>(site2.y()); dif1 = static_cast<int_x2_type>(site2.x()) - static_cast<int_x2_type>(site3.x1()); big_int_type B = line_a * dif1 - line_b * dif0; big_int_type sum_AB = A + B; if (is_zero(denom)) { big_int_type numer = teta * teta - sum_AB * sum_AB; denom = teta * sum_AB; cA[0] = denom * sum_x * 2 + numer * vec_x; cB[0] = segm_len; cA[1] = denom * sum_AB * 2 + numer * teta; cB[1] = 1; cA[2] = denom * sum_y * 2 + numer * vec_y; fpt_type inv_denom = to_fpt(1.0) / to_fpt(denom); if (recompute_c_x) c_event.x(to_fpt(0.25) * to_fpt(cA[0]) * inv_denom); if (recompute_c_y) c_event.y(to_fpt(0.25) * to_fpt(cA[2]) * inv_denom); if (recompute_lower_x) { c_event.lower_x(to_fpt(0.25) * to_fpt(sqrt_expr_.eval2(cA, cB)) * inv_denom / get_sqrt(to_fpt(segm_len))); } return; } big_int_type det = (teta * teta + denom * denom) * A * B * 4; fpt_type inv_denom_sqr = to_fpt(1.0) / to_fpt(denom); inv_denom_sqr *= inv_denom_sqr; if (recompute_c_x || recompute_lower_x) { cA[0] = sum_x * denom * denom + teta * sum_AB * vec_x; cB[0] = 1; cA[1] = (segment_index == 2) ? -vec_x : vec_x; cB[1] = det; if (recompute_c_x) { c_event.x(to_fpt(0.5) * to_fpt(sqrt_expr_.eval2(cA, cB)) * inv_denom_sqr); } } if (recompute_c_y || recompute_lower_x) { cA[2] = sum_y * denom * denom + teta * sum_AB * vec_y; cB[2] = 1; cA[3] = (segment_index == 2) ? -vec_y : vec_y; cB[3] = det; if (recompute_c_y) { c_event.y(to_fpt(0.5) * to_fpt(sqrt_expr_.eval2(&cA[2], &cB[2])) * inv_denom_sqr); } } if (recompute_lower_x) { cB[0] = cB[0] * segm_len; cB[1] = cB[1] * segm_len; cA[2] = sum_AB * (denom * denom + teta * teta); cB[2] = 1; cA[3] = (segment_index == 2) ? -teta : teta; cB[3] = det; c_event.lower_x(to_fpt(0.5) * to_fpt(sqrt_expr_.eval4(cA, cB)) * inv_denom_sqr / get_sqrt(to_fpt(segm_len))); } } // Recompute parameters of the circle event using high-precision library. void pss(const site_type& site1, const site_type& site2, const site_type& site3, int point_index, circle_type& c_event, bool recompute_c_x = true, bool recompute_c_y = true, bool recompute_lower_x = true) { big_int_type a[2], b[2], c[2], cA[4], cB[4]; const point_type& segm_start1 = site2.point1(); const point_type& segm_end1 = site2.point0(); const point_type& segm_start2 = site3.point0(); const point_type& segm_end2 = site3.point1(); a[0] = static_cast<int_x2_type>(segm_end1.x()) - static_cast<int_x2_type>(segm_start1.x()); b[0] = static_cast<int_x2_type>(segm_end1.y()) - static_cast<int_x2_type>(segm_start1.y()); a[1] = static_cast<int_x2_type>(segm_end2.x()) - static_cast<int_x2_type>(segm_start2.x()); b[1] = static_cast<int_x2_type>(segm_end2.y()) - static_cast<int_x2_type>(segm_start2.y()); big_int_type orientation = a[1] * b[0] - a[0] * b[1]; if (is_zero(orientation)) { fpt_type denom = to_fpt(2.0) * to_fpt( static_cast<big_int_type>(a[0] * a[0] + b[0] * b[0])); c[0] = b[0] * (static_cast<int_x2_type>(segm_start2.x()) - static_cast<int_x2_type>(segm_start1.x())) - a[0] * (static_cast<int_x2_type>(segm_start2.y()) - static_cast<int_x2_type>(segm_start1.y())); big_int_type dx = a[0] * (static_cast<int_x2_type>(site1.y()) - static_cast<int_x2_type>(segm_start1.y())) - b[0] * (static_cast<int_x2_type>(site1.x()) - static_cast<int_x2_type>(segm_start1.x())); big_int_type dy = b[0] * (static_cast<int_x2_type>(site1.x()) - static_cast<int_x2_type>(segm_start2.x())) - a[0] * (static_cast<int_x2_type>(site1.y()) - static_cast<int_x2_type>(segm_start2.y())); cB[0] = dx * dy; cB[1] = 1; if (recompute_c_y) { cA[0] = b[0] * ((point_index == 2) ? 2 : -2); cA[1] = a[0] * a[0] * (static_cast<int_x2_type>(segm_start1.y()) + static_cast<int_x2_type>(segm_start2.y())) - a[0] * b[0] * (static_cast<int_x2_type>(segm_start1.x()) + static_cast<int_x2_type>(segm_start2.x()) - static_cast<int_x2_type>(site1.x()) * 2) + b[0] * b[0] * (static_cast<int_x2_type>(site1.y()) * 2); fpt_type c_y = to_fpt(sqrt_expr_.eval2(cA, cB)); c_event.y(c_y / denom); } if (recompute_c_x || recompute_lower_x) { cA[0] = a[0] * ((point_index == 2) ? 2 : -2); cA[1] = b[0] * b[0] * (static_cast<int_x2_type>(segm_start1.x()) + static_cast<int_x2_type>(segm_start2.x())) - a[0] * b[0] * (static_cast<int_x2_type>(segm_start1.y()) + static_cast<int_x2_type>(segm_start2.y()) - static_cast<int_x2_type>(site1.y()) * 2) + a[0] * a[0] * (static_cast<int_x2_type>(site1.x()) * 2); if (recompute_c_x) { fpt_type c_x = to_fpt(sqrt_expr_.eval2(cA, cB)); c_event.x(c_x / denom); } if (recompute_lower_x) { cA[2] = is_neg(c[0]) ? -c[0] : c[0]; cB[2] = a[0] * a[0] + b[0] * b[0]; fpt_type lower_x = to_fpt(sqrt_expr_.eval3(cA, cB)); c_event.lower_x(lower_x / denom); } } return; } c[0] = b[0] * segm_end1.x() - a[0] * segm_end1.y(); c[1] = a[1] * segm_end2.y() - b[1] * segm_end2.x(); big_int_type ix = a[0] * c[1] + a[1] * c[0]; big_int_type iy = b[0] * c[1] + b[1] * c[0]; big_int_type dx = ix - orientation * site1.x(); big_int_type dy = iy - orientation * site1.y(); if (is_zero(dx) && is_zero(dy)) { fpt_type denom = to_fpt(orientation); fpt_type c_x = to_fpt(ix) / denom; fpt_type c_y = to_fpt(iy) / denom; c_event = circle_type(c_x, c_y, c_x); return; } big_int_type sign = ((point_index == 2) ? 1 : -1) * (is_neg(orientation) ? 1 : -1); cA[0] = a[1] * -dx + b[1] * -dy; cA[1] = a[0] * -dx + b[0] * -dy; cA[2] = sign; cA[3] = 0; cB[0] = a[0] * a[0] + b[0] * b[0]; cB[1] = a[1] * a[1] + b[1] * b[1]; cB[2] = a[0] * a[1] + b[0] * b[1]; cB[3] = (a[0] * dy - b[0] * dx) * (a[1] * dy - b[1] * dx) * -2; fpt_type temp = to_fpt( sqrt_expr_evaluator_pss4<big_int_type, efpt_type>(cA, cB)); fpt_type denom = temp * to_fpt(orientation); if (recompute_c_y) { cA[0] = b[1] * (dx * dx + dy * dy) - iy * (dx * a[1] + dy * b[1]); cA[1] = b[0] * (dx * dx + dy * dy) - iy * (dx * a[0] + dy * b[0]); cA[2] = iy * sign; fpt_type cy = to_fpt( sqrt_expr_evaluator_pss4<big_int_type, efpt_type>(cA, cB)); c_event.y(cy / denom); } if (recompute_c_x || recompute_lower_x) { cA[0] = a[1] * (dx * dx + dy * dy) - ix * (dx * a[1] + dy * b[1]); cA[1] = a[0] * (dx * dx + dy * dy) - ix * (dx * a[0] + dy * b[0]); cA[2] = ix * sign; if (recompute_c_x) { fpt_type cx = to_fpt( sqrt_expr_evaluator_pss4<big_int_type, efpt_type>(cA, cB)); c_event.x(cx / denom); } if (recompute_lower_x) { cA[3] = orientation * (dx * dx + dy * dy) * (is_neg(temp) ? -1 : 1); fpt_type lower_x = to_fpt( sqrt_expr_evaluator_pss4<big_int_type, efpt_type>(cA, cB)); c_event.lower_x(lower_x / denom); } } } // Recompute parameters of the circle event using high-precision library. void sss(const site_type& site1, const site_type& site2, const site_type& site3, circle_type& c_event, bool recompute_c_x = true, bool recompute_c_y = true, bool recompute_lower_x = true) { big_int_type a[3], b[3], c[3], cA[4], cB[4]; // cA - corresponds to the cross product. // cB - corresponds to the squared length. a[0] = static_cast<int_x2_type>(site1.x1()) - static_cast<int_x2_type>(site1.x0()); a[1] = static_cast<int_x2_type>(site2.x1()) - static_cast<int_x2_type>(site2.x0()); a[2] = static_cast<int_x2_type>(site3.x1()) - static_cast<int_x2_type>(site3.x0()); b[0] = static_cast<int_x2_type>(site1.y1()) - static_cast<int_x2_type>(site1.y0()); b[1] = static_cast<int_x2_type>(site2.y1()) - static_cast<int_x2_type>(site2.y0()); b[2] = static_cast<int_x2_type>(site3.y1()) - static_cast<int_x2_type>(site3.y0()); c[0] = static_cast<int_x2_type>(site1.x0()) * static_cast<int_x2_type>(site1.y1()) - static_cast<int_x2_type>(site1.y0()) * static_cast<int_x2_type>(site1.x1()); c[1] = static_cast<int_x2_type>(site2.x0()) * static_cast<int_x2_type>(site2.y1()) - static_cast<int_x2_type>(site2.y0()) * static_cast<int_x2_type>(site2.x1()); c[2] = static_cast<int_x2_type>(site3.x0()) * static_cast<int_x2_type>(site3.y1()) - static_cast<int_x2_type>(site3.y0()) * static_cast<int_x2_type>(site3.x1()); for (int i = 0; i < 3; ++i) cB[i] = a[i] * a[i] + b[i] * b[i]; for (int i = 0; i < 3; ++i) { int j = (i+1) % 3; int k = (i+2) % 3; cA[i] = a[j] * b[k] - a[k] * b[j]; } fpt_type denom = to_fpt(sqrt_expr_.eval3(cA, cB)); if (recompute_c_y) { for (int i = 0; i < 3; ++i) { int j = (i+1) % 3; int k = (i+2) % 3; cA[i] = b[j] * c[k] - b[k] * c[j]; } fpt_type c_y = to_fpt(sqrt_expr_.eval3(cA, cB)); c_event.y(c_y / denom); } if (recompute_c_x || recompute_lower_x) { cA[3] = 0; for (int i = 0; i < 3; ++i) { int j = (i+1) % 3; int k = (i+2) % 3; cA[i] = a[j] * c[k] - a[k] * c[j]; if (recompute_lower_x) { cA[3] = cA[3] + cA[i] * b[i]; } } if (recompute_c_x) { fpt_type c_x = to_fpt(sqrt_expr_.eval3(cA, cB)); c_event.x(c_x / denom); } if (recompute_lower_x) { cB[3] = 1; fpt_type lower_x = to_fpt(sqrt_expr_.eval4(cA, cB)); c_event.lower_x(lower_x / denom); } } } private: // Evaluates A[3] + A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) + // A[2] * sqrt(B[3] * (sqrt(B[0] * B[1]) + B[2])). template <typename _int, typename _fpt> _fpt sqrt_expr_evaluator_pss4(_int *A, _int *B) { _int cA[4], cB[4]; if (is_zero(A[3])) { _fpt lh = sqrt_expr_.eval2(A, B); cA[0] = 1; cB[0] = B[0] * B[1]; cA[1] = B[2]; cB[1] = 1; _fpt rh = sqrt_expr_.eval1(A+2, B+3) * get_sqrt(sqrt_expr_.eval2(cA, cB)); if ((!is_neg(lh) && !is_neg(rh)) || (!is_pos(lh) && !is_pos(rh))) return lh + rh; cA[0] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] - A[2] * A[2] * B[3] * B[2]; cB[0] = 1; cA[1] = A[0] * A[1] * 2 - A[2] * A[2] * B[3]; cB[1] = B[0] * B[1]; _fpt numer = sqrt_expr_.eval2(cA, cB); return numer / (lh - rh); } cA[0] = 1; cB[0] = B[0] * B[1]; cA[1] = B[2]; cB[1] = 1; _fpt rh = sqrt_expr_.eval1(A+2, B+3) * get_sqrt(sqrt_expr_.eval2(cA, cB)); cA[0] = A[0]; cB[0] = B[0]; cA[1] = A[1]; cB[1] = B[1]; cA[2] = A[3]; cB[2] = 1; _fpt lh = sqrt_expr_.eval3(cA, cB); if ((!is_neg(lh) && !is_neg(rh)) || (!is_pos(lh) && !is_pos(rh))) return lh + rh; cA[0] = A[3] * A[0] * 2; cA[1] = A[3] * A[1] * 2; cA[2] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] + A[3] * A[3] - A[2] * A[2] * B[2] * B[3]; cA[3] = A[0] * A[1] * 2 - A[2] * A[2] * B[3]; cB[3] = B[0] * B[1]; _fpt numer = sqrt_expr_evaluator_pss3<_int, _fpt>(cA, cB); return numer / (lh - rh); } template <typename _int, typename _fpt> // Evaluates A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) + // A[2] + A[3] * sqrt(B[0] * B[1]). // B[3] = B[0] * B[1]. _fpt sqrt_expr_evaluator_pss3(_int *A, _int *B) { _int cA[2], cB[2]; _fpt lh = sqrt_expr_.eval2(A, B); _fpt rh = sqrt_expr_.eval2(A+2, B+2); if ((!is_neg(lh) && !is_neg(rh)) || (!is_pos(lh) && !is_pos(rh))) return lh + rh; cA[0] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] - A[2] * A[2] - A[3] * A[3] * B[0] * B[1]; cB[0] = 1; cA[1] = (A[0] * A[1] - A[2] * A[3]) * 2; cB[1] = B[3]; _fpt numer = sqrt_expr_.eval2(cA, cB); return numer / (lh - rh); } robust_sqrt_expr_type sqrt_expr_; to_fpt_converter to_fpt; }; template <typename Site, typename Circle> class lazy_circle_formation_functor { public: typedef robust_fpt<fpt_type> robust_fpt_type; typedef robust_dif<robust_fpt_type> robust_dif_type; typedef typename Site::point_type point_type; typedef Site site_type; typedef Circle circle_type; typedef mp_circle_formation_functor<site_type, circle_type> exact_circle_formation_functor_type; void ppp(const site_type& site1, const site_type& site2, const site_type& site3, circle_type& c_event) { fpt_type dif_x1 = to_fpt(site1.x()) - to_fpt(site2.x()); fpt_type dif_x2 = to_fpt(site2.x()) - to_fpt(site3.x()); fpt_type dif_y1 = to_fpt(site1.y()) - to_fpt(site2.y()); fpt_type dif_y2 = to_fpt(site2.y()) - to_fpt(site3.y()); fpt_type orientation = robust_cross_product( static_cast<int_x2_type>(site1.x()) - static_cast<int_x2_type>(site2.x()), static_cast<int_x2_type>(site2.x()) - static_cast<int_x2_type>(site3.x()), static_cast<int_x2_type>(site1.y()) - static_cast<int_x2_type>(site2.y()), static_cast<int_x2_type>(site2.y()) - static_cast<int_x2_type>(site3.y())); robust_fpt_type inv_orientation(to_fpt(0.5) / orientation, to_fpt(2.0)); fpt_type sum_x1 = to_fpt(site1.x()) + to_fpt(site2.x()); fpt_type sum_x2 = to_fpt(site2.x()) + to_fpt(site3.x()); fpt_type sum_y1 = to_fpt(site1.y()) + to_fpt(site2.y()); fpt_type sum_y2 = to_fpt(site2.y()) + to_fpt(site3.y()); fpt_type dif_x3 = to_fpt(site1.x()) - to_fpt(site3.x()); fpt_type dif_y3 = to_fpt(site1.y()) - to_fpt(site3.y()); robust_dif_type c_x, c_y; c_x += robust_fpt_type(dif_x1 * sum_x1 * dif_y2, to_fpt(2.0)); c_x += robust_fpt_type(dif_y1 * sum_y1 * dif_y2, to_fpt(2.0)); c_x -= robust_fpt_type(dif_x2 * sum_x2 * dif_y1, to_fpt(2.0)); c_x -= robust_fpt_type(dif_y2 * sum_y2 * dif_y1, to_fpt(2.0)); c_y += robust_fpt_type(dif_x2 * sum_x2 * dif_x1, to_fpt(2.0)); c_y += robust_fpt_type(dif_y2 * sum_y2 * dif_x1, to_fpt(2.0)); c_y -= robust_fpt_type(dif_x1 * sum_x1 * dif_x2, to_fpt(2.0)); c_y -= robust_fpt_type(dif_y1 * sum_y1 * dif_x2, to_fpt(2.0)); robust_dif_type lower_x(c_x); lower_x -= robust_fpt_type(get_sqrt( (dif_x1 * dif_x1 + dif_y1 * dif_y1) * (dif_x2 * dif_x2 + dif_y2 * dif_y2) * (dif_x3 * dif_x3 + dif_y3 * dif_y3)), to_fpt(5.0)); c_event = circle_type( c_x.dif().fpv() * inv_orientation.fpv(), c_y.dif().fpv() * inv_orientation.fpv(), lower_x.dif().fpv() * inv_orientation.fpv()); bool recompute_c_x = c_x.dif().ulp() > ULPS; bool recompute_c_y = c_y.dif().ulp() > ULPS; bool recompute_lower_x = lower_x.dif().ulp() > ULPS; if (recompute_c_x || recompute_c_y || recompute_lower_x) { exact_circle_formation_functor_.ppp( site1, site2, site3, c_event, recompute_c_x, recompute_c_y, recompute_lower_x); } } void pps(const site_type& site1, const site_type& site2, const site_type& site3, int segment_index, circle_type& c_event) { fpt_type line_a = to_fpt(site3.y1()) - to_fpt(site3.y0()); fpt_type line_b = to_fpt(site3.x0()) - to_fpt(site3.x1()); fpt_type vec_x = to_fpt(site2.y()) - to_fpt(site1.y()); fpt_type vec_y = to_fpt(site1.x()) - to_fpt(site2.x()); robust_fpt_type teta(robust_cross_product( static_cast<int_x2_type>(site3.y1()) - static_cast<int_x2_type>(site3.y0()), static_cast<int_x2_type>(site3.x0()) - static_cast<int_x2_type>(site3.x1()), static_cast<int_x2_type>(site2.x()) - static_cast<int_x2_type>(site1.x()), static_cast<int_x2_type>(site2.y()) - static_cast<int_x2_type>(site1.y())), to_fpt(1.0)); robust_fpt_type A(robust_cross_product( static_cast<int_x2_type>(site3.y0()) - static_cast<int_x2_type>(site3.y1()), static_cast<int_x2_type>(site3.x0()) - static_cast<int_x2_type>(site3.x1()), static_cast<int_x2_type>(site3.y1()) - static_cast<int_x2_type>(site1.y()), static_cast<int_x2_type>(site3.x1()) - static_cast<int_x2_type>(site1.x())), to_fpt(1.0)); robust_fpt_type B(robust_cross_product( static_cast<int_x2_type>(site3.y0()) - static_cast<int_x2_type>(site3.y1()), static_cast<int_x2_type>(site3.x0()) - static_cast<int_x2_type>(site3.x1()), static_cast<int_x2_type>(site3.y1()) - static_cast<int_x2_type>(site2.y()), static_cast<int_x2_type>(site3.x1()) - static_cast<int_x2_type>(site2.x())), to_fpt(1.0)); robust_fpt_type denom(robust_cross_product( static_cast<int_x2_type>(site1.y()) - static_cast<int_x2_type>(site2.y()), static_cast<int_x2_type>(site1.x()) - static_cast<int_x2_type>(site2.x()), static_cast<int_x2_type>(site3.y1()) - static_cast<int_x2_type>(site3.y0()), static_cast<int_x2_type>(site3.x1()) - static_cast<int_x2_type>(site3.x0())), to_fpt(1.0)); robust_fpt_type inv_segm_len(to_fpt(1.0) / get_sqrt(line_a * line_a + line_b * line_b), to_fpt(3.0)); robust_dif_type t; if (ot::eval(denom) == ot::COLLINEAR) { t += teta / (robust_fpt_type(to_fpt(8.0)) * A); t -= A / (robust_fpt_type(to_fpt(2.0)) * teta); } else { robust_fpt_type det = ((teta * teta + denom * denom) * A * B).sqrt(); if (segment_index == 2) { t -= det / (denom * denom); } else { t += det / (denom * denom); } t += teta * (A + B) / (robust_fpt_type(to_fpt(2.0)) * denom * denom); } robust_dif_type c_x, c_y; c_x += robust_fpt_type(to_fpt(0.5) * (to_fpt(site1.x()) + to_fpt(site2.x()))); c_x += robust_fpt_type(vec_x) * t; c_y += robust_fpt_type(to_fpt(0.5) * (to_fpt(site1.y()) + to_fpt(site2.y()))); c_y += robust_fpt_type(vec_y) * t; robust_dif_type r, lower_x(c_x); r -= robust_fpt_type(line_a) * robust_fpt_type(site3.x0()); r -= robust_fpt_type(line_b) * robust_fpt_type(site3.y0()); r += robust_fpt_type(line_a) * c_x; r += robust_fpt_type(line_b) * c_y; if (r.pos().fpv() < r.neg().fpv()) r = -r; lower_x += r * inv_segm_len; c_event = circle_type( c_x.dif().fpv(), c_y.dif().fpv(), lower_x.dif().fpv()); bool recompute_c_x = c_x.dif().ulp() > ULPS; bool recompute_c_y = c_y.dif().ulp() > ULPS; bool recompute_lower_x = lower_x.dif().ulp() > ULPS; if (recompute_c_x || recompute_c_y || recompute_lower_x) { exact_circle_formation_functor_.pps( site1, site2, site3, segment_index, c_event, recompute_c_x, recompute_c_y, recompute_lower_x); } } void pss(const site_type& site1, const site_type& site2, const site_type& site3, int point_index, circle_type& c_event) { const point_type& segm_start1 = site2.point1(); const point_type& segm_end1 = site2.point0(); const point_type& segm_start2 = site3.point0(); const point_type& segm_end2 = site3.point1(); fpt_type a1 = to_fpt(segm_end1.x()) - to_fpt(segm_start1.x()); fpt_type b1 = to_fpt(segm_end1.y()) - to_fpt(segm_start1.y()); fpt_type a2 = to_fpt(segm_end2.x()) - to_fpt(segm_start2.x()); fpt_type b2 = to_fpt(segm_end2.y()) - to_fpt(segm_start2.y()); bool recompute_c_x, recompute_c_y, recompute_lower_x; robust_fpt_type orientation(robust_cross_product( static_cast<int_x2_type>(segm_end1.y()) - static_cast<int_x2_type>(segm_start1.y()), static_cast<int_x2_type>(segm_end1.x()) - static_cast<int_x2_type>(segm_start1.x()), static_cast<int_x2_type>(segm_end2.y()) - static_cast<int_x2_type>(segm_start2.y()), static_cast<int_x2_type>(segm_end2.x()) - static_cast<int_x2_type>(segm_start2.x())), to_fpt(1.0)); if (ot::eval(orientation) == ot::COLLINEAR) { robust_fpt_type a(a1 * a1 + b1 * b1, to_fpt(2.0)); robust_fpt_type c(robust_cross_product( static_cast<int_x2_type>(segm_end1.y()) - static_cast<int_x2_type>(segm_start1.y()), static_cast<int_x2_type>(segm_end1.x()) - static_cast<int_x2_type>(segm_start1.x()), static_cast<int_x2_type>(segm_start2.y()) - static_cast<int_x2_type>(segm_start1.y()), static_cast<int_x2_type>(segm_start2.x()) - static_cast<int_x2_type>(segm_start1.x())), to_fpt(1.0)); robust_fpt_type det( robust_cross_product( static_cast<int_x2_type>(segm_end1.x()) - static_cast<int_x2_type>(segm_start1.x()), static_cast<int_x2_type>(segm_end1.y()) - static_cast<int_x2_type>(segm_start1.y()), static_cast<int_x2_type>(site1.x()) - static_cast<int_x2_type>(segm_start1.x()), static_cast<int_x2_type>(site1.y()) - static_cast<int_x2_type>(segm_start1.y())) * robust_cross_product( static_cast<int_x2_type>(segm_end1.y()) - static_cast<int_x2_type>(segm_start1.y()), static_cast<int_x2_type>(segm_end1.x()) - static_cast<int_x2_type>(segm_start1.x()), static_cast<int_x2_type>(site1.y()) - static_cast<int_x2_type>(segm_start2.y()), static_cast<int_x2_type>(site1.x()) - static_cast<int_x2_type>(segm_start2.x())), to_fpt(3.0)); robust_dif_type t; t -= robust_fpt_type(a1) * robust_fpt_type(( to_fpt(segm_start1.x()) + to_fpt(segm_start2.x())) * to_fpt(0.5) - to_fpt(site1.x())); t -= robust_fpt_type(b1) * robust_fpt_type(( to_fpt(segm_start1.y()) + to_fpt(segm_start2.y())) * to_fpt(0.5) - to_fpt(site1.y())); if (point_index == 2) { t += det.sqrt(); } else { t -= det.sqrt(); } t /= a; robust_dif_type c_x, c_y; c_x += robust_fpt_type(to_fpt(0.5) * ( to_fpt(segm_start1.x()) + to_fpt(segm_start2.x()))); c_x += robust_fpt_type(a1) * t; c_y += robust_fpt_type(to_fpt(0.5) * ( to_fpt(segm_start1.y()) + to_fpt(segm_start2.y()))); c_y += robust_fpt_type(b1) * t; robust_dif_type lower_x(c_x); if (is_neg(c)) { lower_x -= robust_fpt_type(to_fpt(0.5)) * c / a.sqrt(); } else { lower_x += robust_fpt_type(to_fpt(0.5)) * c / a.sqrt(); } recompute_c_x = c_x.dif().ulp() > ULPS; recompute_c_y = c_y.dif().ulp() > ULPS; recompute_lower_x = lower_x.dif().ulp() > ULPS; c_event = circle_type(c_x.dif().fpv(), c_y.dif().fpv(), lower_x.dif().fpv()); } else { robust_fpt_type sqr_sum1(get_sqrt(a1 * a1 + b1 * b1), to_fpt(2.0)); robust_fpt_type sqr_sum2(get_sqrt(a2 * a2 + b2 * b2), to_fpt(2.0)); robust_fpt_type a(robust_cross_product( static_cast<int_x2_type>(segm_end1.x()) - static_cast<int_x2_type>(segm_start1.x()), static_cast<int_x2_type>(segm_end1.y()) - static_cast<int_x2_type>(segm_start1.y()), static_cast<int_x2_type>(segm_start2.y()) - static_cast<int_x2_type>(segm_end2.y()), static_cast<int_x2_type>(segm_end2.x()) - static_cast<int_x2_type>(segm_start2.x())), to_fpt(1.0)); if (!is_neg(a)) { a += sqr_sum1 * sqr_sum2; } else { a = (orientation * orientation) / (sqr_sum1 * sqr_sum2 - a); } robust_fpt_type or1(robust_cross_product( static_cast<int_x2_type>(segm_end1.y()) - static_cast<int_x2_type>(segm_start1.y()), static_cast<int_x2_type>(segm_end1.x()) - static_cast<int_x2_type>(segm_start1.x()), static_cast<int_x2_type>(segm_end1.y()) - static_cast<int_x2_type>(site1.y()), static_cast<int_x2_type>(segm_end1.x()) - static_cast<int_x2_type>(site1.x())), to_fpt(1.0)); robust_fpt_type or2(robust_cross_product( static_cast<int_x2_type>(segm_end2.x()) - static_cast<int_x2_type>(segm_start2.x()), static_cast<int_x2_type>(segm_end2.y()) - static_cast<int_x2_type>(segm_start2.y()), static_cast<int_x2_type>(segm_end2.x()) - static_cast<int_x2_type>(site1.x()), static_cast<int_x2_type>(segm_end2.y()) - static_cast<int_x2_type>(site1.y())), to_fpt(1.0)); robust_fpt_type det = robust_fpt_type(to_fpt(2.0)) * a * or1 * or2; robust_fpt_type c1(robust_cross_product( static_cast<int_x2_type>(segm_end1.y()) - static_cast<int_x2_type>(segm_start1.y()), static_cast<int_x2_type>(segm_end1.x()) - static_cast<int_x2_type>(segm_start1.x()), static_cast<int_x2_type>(segm_end1.y()), static_cast<int_x2_type>(segm_end1.x())), to_fpt(1.0)); robust_fpt_type c2(robust_cross_product( static_cast<int_x2_type>(segm_end2.x()) - static_cast<int_x2_type>(segm_start2.x()), static_cast<int_x2_type>(segm_end2.y()) - static_cast<int_x2_type>(segm_start2.y()), static_cast<int_x2_type>(segm_end2.x()), static_cast<int_x2_type>(segm_end2.y())), to_fpt(1.0)); robust_fpt_type inv_orientation = robust_fpt_type(to_fpt(1.0)) / orientation; robust_dif_type t, b, ix, iy; ix += robust_fpt_type(a2) * c1 * inv_orientation; ix += robust_fpt_type(a1) * c2 * inv_orientation; iy += robust_fpt_type(b1) * c2 * inv_orientation; iy += robust_fpt_type(b2) * c1 * inv_orientation; b += ix * (robust_fpt_type(a1) * sqr_sum2); b += ix * (robust_fpt_type(a2) * sqr_sum1); b += iy * (robust_fpt_type(b1) * sqr_sum2); b += iy * (robust_fpt_type(b2) * sqr_sum1); b -= sqr_sum1 * robust_fpt_type(robust_cross_product( static_cast<int_x2_type>(segm_end2.x()) - static_cast<int_x2_type>(segm_start2.x()), static_cast<int_x2_type>(segm_end2.y()) - static_cast<int_x2_type>(segm_start2.y()), static_cast<int_x2_type>(-site1.y()), static_cast<int_x2_type>(site1.x())), to_fpt(1.0)); b -= sqr_sum2 * robust_fpt_type(robust_cross_product( static_cast<int_x2_type>(segm_end1.x()) - static_cast<int_x2_type>(segm_start1.x()), static_cast<int_x2_type>(segm_end1.y()) - static_cast<int_x2_type>(segm_start1.y()), static_cast<int_x2_type>(-site1.y()), static_cast<int_x2_type>(site1.x())), to_fpt(1.0)); t -= b; if (point_index == 2) { t += det.sqrt(); } else { t -= det.sqrt(); } t /= (a * a); robust_dif_type c_x(ix), c_y(iy); c_x += t * (robust_fpt_type(a1) * sqr_sum2); c_x += t * (robust_fpt_type(a2) * sqr_sum1); c_y += t * (robust_fpt_type(b1) * sqr_sum2); c_y += t * (robust_fpt_type(b2) * sqr_sum1); if (t.pos().fpv() < t.neg().fpv()) { t = -t; } robust_dif_type lower_x(c_x); if (is_neg(orientation)) { lower_x -= t * orientation; } else { lower_x += t * orientation; } recompute_c_x = c_x.dif().ulp() > ULPS; recompute_c_y = c_y.dif().ulp() > ULPS; recompute_lower_x = lower_x.dif().ulp() > ULPS; c_event = circle_type( c_x.dif().fpv(), c_y.dif().fpv(), lower_x.dif().fpv()); } if (recompute_c_x || recompute_c_y || recompute_lower_x) { exact_circle_formation_functor_.pss( site1, site2, site3, point_index, c_event, recompute_c_x, recompute_c_y, recompute_lower_x); } } void sss(const site_type& site1, const site_type& site2, const site_type& site3, circle_type& c_event) { robust_fpt_type a1(to_fpt(site1.x1()) - to_fpt(site1.x0())); robust_fpt_type b1(to_fpt(site1.y1()) - to_fpt(site1.y0())); robust_fpt_type c1(robust_cross_product( site1.x0(), site1.y0(), site1.x1(), site1.y1()), to_fpt(1.0)); robust_fpt_type a2(to_fpt(site2.x1()) - to_fpt(site2.x0())); robust_fpt_type b2(to_fpt(site2.y1()) - to_fpt(site2.y0())); robust_fpt_type c2(robust_cross_product( site2.x0(), site2.y0(), site2.x1(), site2.y1()), to_fpt(1.0)); robust_fpt_type a3(to_fpt(site3.x1()) - to_fpt(site3.x0())); robust_fpt_type b3(to_fpt(site3.y1()) - to_fpt(site3.y0())); robust_fpt_type c3(robust_cross_product( site3.x0(), site3.y0(), site3.x1(), site3.y1()), to_fpt(1.0)); robust_fpt_type len1 = (a1 * a1 + b1 * b1).sqrt(); robust_fpt_type len2 = (a2 * a2 + b2 * b2).sqrt(); robust_fpt_type len3 = (a3 * a3 + b3 * b3).sqrt(); robust_fpt_type cross_12(robust_cross_product( static_cast<int_x2_type>(site1.x1()) - static_cast<int_x2_type>(site1.x0()), static_cast<int_x2_type>(site1.y1()) - static_cast<int_x2_type>(site1.y0()), static_cast<int_x2_type>(site2.x1()) - static_cast<int_x2_type>(site2.x0()), static_cast<int_x2_type>(site2.y1()) - static_cast<int_x2_type>(site2.y0())), to_fpt(1.0)); robust_fpt_type cross_23(robust_cross_product( static_cast<int_x2_type>(site2.x1()) - static_cast<int_x2_type>(site2.x0()), static_cast<int_x2_type>(site2.y1()) - static_cast<int_x2_type>(site2.y0()), static_cast<int_x2_type>(site3.x1()) - static_cast<int_x2_type>(site3.x0()), static_cast<int_x2_type>(site3.y1()) - static_cast<int_x2_type>(site3.y0())), to_fpt(1.0)); robust_fpt_type cross_31(robust_cross_product( static_cast<int_x2_type>(site3.x1()) - static_cast<int_x2_type>(site3.x0()), static_cast<int_x2_type>(site3.y1()) - static_cast<int_x2_type>(site3.y0()), static_cast<int_x2_type>(site1.x1()) - static_cast<int_x2_type>(site1.x0()), static_cast<int_x2_type>(site1.y1()) - static_cast<int_x2_type>(site1.y0())), to_fpt(1.0)); // denom = cross_12 * len3 + cross_23 * len1 + cross_31 * len2. robust_dif_type denom; denom += cross_12 * len3; denom += cross_23 * len1; denom += cross_31 * len2; // denom * r = (b2 * c_x - a2 * c_y - c2 * denom) / len2. robust_dif_type r; r -= cross_12 * c3; r -= cross_23 * c1; r -= cross_31 * c2; robust_dif_type c_x; c_x += a1 * c2 * len3; c_x -= a2 * c1 * len3; c_x += a2 * c3 * len1; c_x -= a3 * c2 * len1; c_x += a3 * c1 * len2; c_x -= a1 * c3 * len2; robust_dif_type c_y; c_y += b1 * c2 * len3; c_y -= b2 * c1 * len3; c_y += b2 * c3 * len1; c_y -= b3 * c2 * len1; c_y += b3 * c1 * len2; c_y -= b1 * c3 * len2; robust_dif_type lower_x = c_x + r; robust_fpt_type denom_dif = denom.dif(); robust_fpt_type c_x_dif = c_x.dif() / denom_dif; robust_fpt_type c_y_dif = c_y.dif() / denom_dif; robust_fpt_type lower_x_dif = lower_x.dif() / denom_dif; bool recompute_c_x = c_x_dif.ulp() > ULPS; bool recompute_c_y = c_y_dif.ulp() > ULPS; bool recompute_lower_x = lower_x_dif.ulp() > ULPS; c_event = circle_type(c_x_dif.fpv(), c_y_dif.fpv(), lower_x_dif.fpv()); if (recompute_c_x || recompute_c_y || recompute_lower_x) { exact_circle_formation_functor_.sss( site1, site2, site3, c_event, recompute_c_x, recompute_c_y, recompute_lower_x); } } private: exact_circle_formation_functor_type exact_circle_formation_functor_; to_fpt_converter to_fpt; }; template <typename Site, typename Circle, typename CEP = circle_existence_predicate<Site>, typename CFF = lazy_circle_formation_functor<Site, Circle> > class circle_formation_predicate { public: typedef Site site_type; typedef Circle circle_type; typedef CEP circle_existence_predicate_type; typedef CFF circle_formation_functor_type; // Create a circle event from the given three sites. // Returns true if the circle event exists, else false. // If exists circle event is saved into the c_event variable. bool operator()(const site_type& site1, const site_type& site2, const site_type& site3, circle_type& circle) { if (!site1.is_segment()) { if (!site2.is_segment()) { if (!site3.is_segment()) { // (point, point, point) sites. if (!circle_existence_predicate_.ppp(site1, site2, site3)) return false; circle_formation_functor_.ppp(site1, site2, site3, circle); } else { // (point, point, segment) sites. if (!circle_existence_predicate_.pps(site1, site2, site3, 3)) return false; circle_formation_functor_.pps(site1, site2, site3, 3, circle); } } else { if (!site3.is_segment()) { // (point, segment, point) sites. if (!circle_existence_predicate_.pps(site1, site3, site2, 2)) return false; circle_formation_functor_.pps(site1, site3, site2, 2, circle); } else { // (point, segment, segment) sites. if (!circle_existence_predicate_.pss(site1, site2, site3, 1)) return false; circle_formation_functor_.pss(site1, site2, site3, 1, circle); } } } else { if (!site2.is_segment()) { if (!site3.is_segment()) { // (segment, point, point) sites. if (!circle_existence_predicate_.pps(site2, site3, site1, 1)) return false; circle_formation_functor_.pps(site2, site3, site1, 1, circle); } else { // (segment, point, segment) sites. if (!circle_existence_predicate_.pss(site2, site1, site3, 2)) return false; circle_formation_functor_.pss(site2, site1, site3, 2, circle); } } else { if (!site3.is_segment()) { // (segment, segment, point) sites. if (!circle_existence_predicate_.pss(site3, site1, site2, 3)) return false; circle_formation_functor_.pss(site3, site1, site2, 3, circle); } else { // (segment, segment, segment) sites. if (!circle_existence_predicate_.sss(site1, site2, site3)) return false; circle_formation_functor_.sss(site1, site2, site3, circle); } } } if (lies_outside_vertical_segment(circle, site1) || lies_outside_vertical_segment(circle, site2) || lies_outside_vertical_segment(circle, site3)) { return false; } return true; } private: bool lies_outside_vertical_segment( const circle_type& c, const site_type& s) { if (!s.is_segment() || !is_vertical(s)) { return false; } fpt_type y0 = to_fpt(s.is_inverse() ? s.y1() : s.y0()); fpt_type y1 = to_fpt(s.is_inverse() ? s.y0() : s.y1()); return ulp_cmp(c.y(), y0, ULPS) == ulp_cmp_type::LESS || ulp_cmp(c.y(), y1, ULPS) == ulp_cmp_type::MORE; } private: to_fpt_converter to_fpt; ulp_cmp_type ulp_cmp; circle_existence_predicate_type circle_existence_predicate_; circle_formation_functor_type circle_formation_functor_; }; }; } // detail } // polygon } // boost #endif // BOOST_POLYGON_DETAIL_VORONOI_PREDICATES detail/polygon_sort_adaptor.hpp 0000644 00000004224 15125572616 0013003 0 ustar 00 /* 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_SORT_ADAPTOR_HPP #define BOOST_POLYGON_SORT_ADAPTOR_HPP #ifdef __ICC #pragma warning(disable:2022) #pragma warning(disable:2023) #endif #include <algorithm> //! @brief polygon_sort_adaptor default implementation that calls std::sort namespace boost { namespace polygon { template<typename iterator_type> struct dummy_to_delay_instantiation{ typedef int unit_type; // default GTL unit }; //! @brief polygon_sort_adaptor default implementation that calls std::sort template<typename T> struct polygon_sort_adaptor { //! @brief wrapper that mimics std::sort() function and takes // the same arguments template<typename RandomAccessIterator_Type> static void sort(RandomAccessIterator_Type _First, RandomAccessIterator_Type _Last) { std::sort(_First, _Last); } //! @brief wrapper that mimics std::sort() function overload and takes // the same arguments template<typename RandomAccessIterator_Type, typename Pred_Type> static void sort(RandomAccessIterator_Type _First, RandomAccessIterator_Type _Last, const Pred_Type& _Comp) { std::sort(_First, _Last, _Comp); } }; //! @brief user level wrapper for sorting quantities template <typename iter_type> void polygon_sort(iter_type _b_, iter_type _e_) { polygon_sort_adaptor<typename dummy_to_delay_instantiation<iter_type>::unit_type>::sort(_b_, _e_); } //! @brief user level wrapper for sorting quantities that takes predicate // as additional argument template <typename iter_type, typename pred_type> void polygon_sort(iter_type _b_, iter_type _e_, const pred_type& _pred_) { polygon_sort_adaptor<typename dummy_to_delay_instantiation<iter_type>::unit_type>::sort(_b_, _e_, _pred_); } } // namespace polygon } // namespace boost #endif detail/polygon_45_formation.hpp 0000644 00000260142 15125572616 0012613 0 ustar 00 /* 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_45_FORMATION_HPP #define BOOST_POLYGON_POLYGON_45_FORMATION_HPP namespace boost { namespace polygon{ template <typename T, typename T2> struct PolyLineByConcept {}; template <typename T> class PolyLine45PolygonData; template <typename T> class PolyLine45HoleData; //polygon45formation algorithm template <typename Unit> struct polygon_45_formation : public boolean_op_45<Unit> { typedef point_data<Unit> Point; typedef polygon_45_data<Unit> Polygon45; typedef polygon_45_with_holes_data<Unit> Polygon45WithHoles; typedef typename boolean_op_45<Unit>::Vertex45 Vertex45; typedef typename boolean_op_45<Unit>::lessVertex45 lessVertex45; typedef typename boolean_op_45<Unit>::Count2 Count2; typedef typename boolean_op_45<Unit>::Scan45Count Scan45Count; typedef std::pair<Point, Scan45Count> Scan45Vertex; typedef typename boolean_op_45<Unit>::template Scan45<Count2, typename boolean_op_45<Unit>::template boolean_op_45_output_functor<0> > Scan45; class PolyLine45 { public: typedef typename std::list<Point>::const_iterator iterator; // default constructor of point does not initialize x and y inline PolyLine45() : points() {} //do nothing default constructor // initialize a polygon from x,y values, it is assumed that the first is an x // and that the input is a well behaved polygon template<class iT> inline PolyLine45& set(iT inputBegin, iT inputEnd) { points.clear(); //just in case there was some old data there while(inputBegin != inputEnd) { points.insert(points.end(), *inputBegin); ++inputBegin; } return *this; } // copy constructor (since we have dynamic memory) inline PolyLine45(const PolyLine45& that) : points(that.points) {} // assignment operator (since we have dynamic memory do a deep copy) inline PolyLine45& operator=(const PolyLine45& that) { points = that.points; return *this; } // get begin iterator, returns a pointer to a const Unit inline iterator begin() const { return points.begin(); } // get end iterator, returns a pointer to a const Unit inline iterator end() const { return points.end(); } inline std::size_t size() const { return points.size(); } //public data member std::list<Point> points; }; class ActiveTail45 { private: //data PolyLine45* tailp_; ActiveTail45 *otherTailp_; std::list<ActiveTail45*> holesList_; bool head_; public: /** * @brief iterator over coordinates of the figure */ typedef typename PolyLine45::iterator iterator; /** * @brief iterator over holes contained within the figure */ typedef typename std::list<ActiveTail45*>::const_iterator iteratorHoles; //default constructor inline ActiveTail45() : tailp_(0), otherTailp_(0), holesList_(), head_(0) {} //constructor inline ActiveTail45(const Vertex45& vertex, ActiveTail45* otherTailp = 0) : tailp_(0), otherTailp_(0), holesList_(), head_(0) { tailp_ = new PolyLine45; tailp_->points.push_back(vertex.pt); bool headArray[4] = {false, true, true, true}; bool inverted = vertex.count == -1; head_ = headArray[vertex.rise+1] ^ inverted; otherTailp_ = otherTailp; } inline ActiveTail45(Point point, ActiveTail45* otherTailp, bool head = true) : tailp_(0), otherTailp_(0), holesList_(), head_(0) { tailp_ = new PolyLine45; tailp_->points.push_back(point); head_ = head; otherTailp_ = otherTailp; } inline ActiveTail45(ActiveTail45* otherTailp) : tailp_(0), otherTailp_(0), holesList_(), head_(0) { tailp_ = otherTailp->tailp_; otherTailp_ = otherTailp; } //copy constructor inline ActiveTail45(const ActiveTail45& that) : tailp_(0), otherTailp_(0), holesList_(), head_(0) { (*this) = that; } //destructor inline ~ActiveTail45() { destroyContents(); } //assignment operator inline ActiveTail45& operator=(const ActiveTail45& that) { tailp_ = new PolyLine45(*(that.tailp_)); head_ = that.head_; otherTailp_ = that.otherTailp_; holesList_ = that.holesList_; return *this; } //equivalence operator inline bool operator==(const ActiveTail45& b) const { return tailp_ == b.tailp_ && head_ == b.head_; } /** * @brief get the pointer to the polyline that this is an active tail of */ inline PolyLine45* getTail() const { return tailp_; } /** * @brief get the pointer to the polyline at the other end of the chain */ inline PolyLine45* getOtherTail() const { return otherTailp_->tailp_; } /** * @brief get the pointer to the activetail at the other end of the chain */ inline ActiveTail45* getOtherActiveTail() const { return otherTailp_; } /** * @brief test if another active tail is the other end of the chain */ inline bool isOtherTail(const ActiveTail45& b) const { return &b == otherTailp_; } /** * @brief update this end of chain pointer to new polyline */ inline ActiveTail45& updateTail(PolyLine45* newTail) { tailp_ = newTail; return *this; } inline bool join(ActiveTail45* tail) { if(tail == otherTailp_) { //std::cout << "joining to other tail!\n"; return false; } if(tail->head_ == head_) { //std::cout << "joining head to head!\n"; return false; } if(!tailp_) { //std::cout << "joining empty tail!\n"; return false; } if(!(otherTailp_->head_)) { otherTailp_->copyHoles(*tail); otherTailp_->copyHoles(*this); } else { tail->otherTailp_->copyHoles(*this); tail->otherTailp_->copyHoles(*tail); } PolyLine45* tail1 = tailp_; PolyLine45* tail2 = tail->tailp_; if(head_) std::swap(tail1, tail2); tail1->points.splice(tail1->points.end(), tail2->points); delete tail2; otherTailp_->tailp_ = tail1; tail->otherTailp_->tailp_ = tail1; otherTailp_->otherTailp_ = tail->otherTailp_; tail->otherTailp_->otherTailp_ = otherTailp_; tailp_ = 0; tail->tailp_ = 0; tail->otherTailp_ = 0; otherTailp_ = 0; return true; } /** * @brief associate a hole to this active tail by the specified policy */ inline ActiveTail45* addHole(ActiveTail45* hole) { holesList_.push_back(hole); copyHoles(*hole); copyHoles(*(hole->otherTailp_)); return this; } /** * @brief get the list of holes */ inline const std::list<ActiveTail45*>& getHoles() const { return holesList_; } /** * @brief copy holes from that to this */ inline void copyHoles(ActiveTail45& that) { holesList_.splice(holesList_.end(), that.holesList_); } /** * @brief find out if solid to right */ inline bool solidToRight() const { return !head_; } inline bool solidToLeft() const { return head_; } /** * @brief get vertex */ inline Point getPoint() const { if(head_) return tailp_->points.front(); return tailp_->points.back(); } /** * @brief add a coordinate to the polygon at this active tail end, properly handle degenerate edges by removing redundant coordinate */ inline void pushPoint(Point point) { if(head_) { //if(tailp_->points.size() < 2) { // tailp_->points.push_front(point); // return; //} typename std::list<Point>::iterator iter = tailp_->points.begin(); if(iter == tailp_->points.end()) { tailp_->points.push_front(point); return; } Unit firstY = (*iter).y(); Unit firstX = (*iter).x(); ++iter; if(iter == tailp_->points.end()) { tailp_->points.push_front(point); return; } if((iter->y() == point.y() && firstY == point.y()) || (iter->x() == point.x() && firstX == point.x())){ --iter; *iter = point; } else { tailp_->points.push_front(point); } return; } //if(tailp_->points.size() < 2) { // tailp_->points.push_back(point); // return; //} typename std::list<Point>::reverse_iterator iter = tailp_->points.rbegin(); if(iter == tailp_->points.rend()) { tailp_->points.push_back(point); return; } Unit firstY = (*iter).y(); Unit firstX = (*iter).x(); ++iter; if(iter == tailp_->points.rend()) { tailp_->points.push_back(point); return; } if((iter->y() == point.y() && firstY == point.y()) || (iter->x() == point.x() && firstX == point.x())){ --iter; *iter = point; } else { tailp_->points.push_back(point); } } /** * @brief joins the two chains that the two active tail tails are ends of * checks for closure of figure and writes out polygons appropriately * returns a handle to a hole if one is closed */ template <class cT> static inline ActiveTail45* joinChains(Point point, ActiveTail45* at1, ActiveTail45* at2, bool solid, cT& output) { if(at1->otherTailp_ == at2) { //if(at2->otherTailp_ != at1) std::cout << "half closed error\n"; //we are closing a figure at1->pushPoint(point); at2->pushPoint(point); if(solid) { //we are closing a solid figure, write to output //std::cout << "test1\n"; at1->copyHoles(*(at1->otherTailp_)); //std::cout << "test2\n"; //Polygon45WithHolesImpl<PolyLine45PolygonData> poly(polyData); //std::cout << poly << "\n"; //std::cout << "test3\n"; typedef typename cT::value_type pType; output.push_back(pType()); typedef typename geometry_concept<pType>::type cType; typename PolyLineByConcept<Unit, cType>::type polyData(at1); assign(output.back(), polyData); //std::cout << "test4\n"; //std::cout << "delete " << at1->otherTailp_ << "\n"; //at1->print(); //at1->otherTailp_->print(); delete at1->otherTailp_; //at1->print(); //at1->otherTailp_->print(); //std::cout << "test5\n"; //std::cout << "delete " << at1 << "\n"; delete at1; //std::cout << "test6\n"; return 0; } else { //we are closing a hole, return the tail end active tail of the figure return at1; } } //we are not closing a figure at1->pushPoint(point); at1->join(at2); delete at1; delete at2; return 0; } inline void destroyContents() { if(otherTailp_) { //std::cout << "delete p " << tailp_ << "\n"; if(tailp_) delete tailp_; tailp_ = 0; otherTailp_->otherTailp_ = 0; otherTailp_->tailp_ = 0; otherTailp_ = 0; } for(typename std::list<ActiveTail45*>::iterator itr = holesList_.begin(); itr != holesList_.end(); ++itr) { //std::cout << "delete p " << (*itr) << "\n"; if(*itr) { if((*itr)->otherTailp_) { delete (*itr)->otherTailp_; (*itr)->otherTailp_ = 0; } delete (*itr); } (*itr) = 0; } holesList_.clear(); } // inline void print() { // std::cout << this << " " << tailp_ << " " << otherTailp_ << " " << holesList_.size() << " " << head_ << "\n"; // } static inline std::pair<ActiveTail45*, ActiveTail45*> createActiveTail45sAsPair(Point point, bool solid, ActiveTail45* phole, bool fractureHoles) { ActiveTail45* at1 = 0; ActiveTail45* at2 = 0; if(phole && fractureHoles) { //std::cout << "adding hole\n"; at1 = phole; //assert solid == false, we should be creating a corner with solid below and to the left if there was a hole at2 = at1->getOtherActiveTail(); at2->pushPoint(point); at1->pushPoint(point); } else { at1 = new ActiveTail45(point, at2, solid); at2 = new ActiveTail45(at1); at1->otherTailp_ = at2; at2->head_ = !solid; if(phole) at2->addHole(phole); //assert fractureHoles == false } return std::pair<ActiveTail45*, ActiveTail45*>(at1, at2); } }; template <typename ct> class Vertex45CountT { public: typedef ct count_type; inline Vertex45CountT() #ifndef BOOST_POLYGON_MSVC : counts() #endif { counts[0] = counts[1] = counts[2] = counts[3] = 0; } //inline Vertex45CountT(ct count) { counts[0] = counts[1] = counts[2] = counts[3] = count; } inline Vertex45CountT(const ct& count1, const ct& count2, const ct& count3, const ct& count4) #ifndef BOOST_POLYGON_MSVC : counts() #endif { counts[0] = count1; counts[1] = count2; counts[2] = count3; counts[3] = count4; } inline Vertex45CountT(const Vertex45& vertex) #ifndef BOOST_POLYGON_MSVC : counts() #endif { counts[0] = counts[1] = counts[2] = counts[3] = 0; (*this) += vertex; } inline Vertex45CountT(const Vertex45CountT& count) #ifndef BOOST_POLYGON_MSVC : counts() #endif { (*this) = count; } inline bool operator==(const Vertex45CountT& count) const { for(unsigned int i = 0; i < 4; ++i) { if(counts[i] != count.counts[i]) return false; } return true; } inline bool operator!=(const Vertex45CountT& count) const { return !((*this) == count); } inline Vertex45CountT& operator=(ct count) { counts[0] = counts[1] = counts[2] = counts[3] = count; return *this; } inline Vertex45CountT& operator=(const Vertex45CountT& count) { for(unsigned int i = 0; i < 4; ++i) { counts[i] = count.counts[i]; } return *this; } inline ct& operator[](int index) { return counts[index]; } inline ct operator[](int index) const {return counts[index]; } inline Vertex45CountT& operator+=(const Vertex45CountT& count){ for(unsigned int i = 0; i < 4; ++i) { counts[i] += count.counts[i]; } return *this; } inline Vertex45CountT& operator-=(const Vertex45CountT& count){ for(unsigned int i = 0; i < 4; ++i) { counts[i] -= count.counts[i]; } return *this; } inline Vertex45CountT operator+(const Vertex45CountT& count) const { return Vertex45CountT(*this)+=count; } inline Vertex45CountT operator-(const Vertex45CountT& count) const { return Vertex45CountT(*this)-=count; } inline Vertex45CountT invert() const { return Vertex45CountT()-=(*this); } inline Vertex45CountT& operator+=(const Vertex45& element){ counts[element.rise+1] += element.count; return *this; } inline bool is_45() const { return counts[0] != 0 || counts[2] != 0; } private: ct counts[4]; }; typedef Vertex45CountT<int> Vertex45Count; // inline std::ostream& operator<< (std::ostream& o, const Vertex45Count& c) { // o << c[0] << ", " << c[1] << ", "; // o << c[2] << ", " << c[3]; // return o; // } template <typename ct> class Vertex45CompactT { public: Point pt; ct count; typedef typename boolean_op_45<Unit>::template Vertex45T<typename ct::count_type> Vertex45T; inline Vertex45CompactT() : pt(), count() {} inline Vertex45CompactT(const Point& point, int riseIn, int countIn) : pt(point), count() { count[riseIn+1] = countIn; } template <typename ct2> inline Vertex45CompactT(const typename boolean_op_45<Unit>::template Vertex45T<ct2>& vertex) : pt(vertex.pt), count() { count[vertex.rise+1] = vertex.count; } inline Vertex45CompactT(const Vertex45CompactT& vertex) : pt(vertex.pt), count(vertex.count) {} inline Vertex45CompactT& operator=(const Vertex45CompactT& vertex){ pt = vertex.pt; count = vertex.count; return *this; } inline bool operator==(const Vertex45CompactT& vertex) const { return pt == vertex.pt && count == vertex.count; } inline bool operator!=(const Vertex45CompactT& vertex) const { return !((*this) == vertex); } inline bool operator<(const Vertex45CompactT& vertex) const { if(pt.x() < vertex.pt.x()) return true; if(pt.x() == vertex.pt.x()) { return pt.y() < vertex.pt.y(); } return false; } inline bool operator>(const Vertex45CompactT& vertex) const { return vertex < (*this); } inline bool operator<=(const Vertex45CompactT& vertex) const { return !((*this) > vertex); } inline bool operator>=(const Vertex45CompactT& vertex) const { return !((*this) < vertex); } inline bool haveVertex45(int index) const { return count[index]; } inline Vertex45T operator[](int index) const { return Vertex45T(pt, index-1, count[index]); } }; typedef Vertex45CompactT<Vertex45Count> Vertex45Compact; // inline std::ostream& operator<< (std::ostream& o, const Vertex45Compact& c) { // o << c.pt << ", " << c.count; // return o; // } class Polygon45Formation { private: //definitions typedef std::map<Vertex45, ActiveTail45*, lessVertex45> Polygon45FormationData; typedef typename Polygon45FormationData::iterator iterator; typedef typename Polygon45FormationData::const_iterator const_iterator; //data Polygon45FormationData scanData_; Unit x_; int justBefore_; int fractureHoles_; public: inline Polygon45Formation() : scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false), fractureHoles_(0) { lessVertex45 lessElm(&x_, &justBefore_); scanData_ = Polygon45FormationData(lessElm); } inline Polygon45Formation(bool fractureHoles) : scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false), fractureHoles_(fractureHoles) { lessVertex45 lessElm(&x_, &justBefore_); scanData_ = Polygon45FormationData(lessElm); } inline Polygon45Formation(const Polygon45Formation& that) : scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false), fractureHoles_(0) { (*this) = that; } inline Polygon45Formation& operator=(const Polygon45Formation& that) { x_ = that.x_; justBefore_ = that.justBefore_; fractureHoles_ = that.fractureHoles_; lessVertex45 lessElm(&x_, &justBefore_); scanData_ = Polygon45FormationData(lessElm); for(const_iterator itr = that.scanData_.begin(); itr != that.scanData_.end(); ++itr){ scanData_.insert(scanData_.end(), *itr); } return *this; } //cT is an output container of Polygon45 or Polygon45WithHoles //iT is an iterator over Vertex45 elements //inputBegin - inputEnd is a range of sorted iT that represents //one or more scanline stops worth of data template <class cT, class iT> void scan(cT& output, iT inputBegin, iT inputEnd) { //std::cout << "1\n"; while(inputBegin != inputEnd) { //std::cout << "2\n"; x_ = (*inputBegin).pt.x(); //std::cout << "SCAN FORMATION " << x_ << "\n"; //std::cout << "x_ = " << x_ << "\n"; //std::cout << "scan line size: " << scanData_.size() << "\n"; inputBegin = processEvent_(output, inputBegin, inputEnd); } } private: //functions template <class cT, class cT2> inline std::pair<int, ActiveTail45*> processPoint_(cT& output, cT2& elements, Point point, Vertex45Count& counts, ActiveTail45** tails, Vertex45Count& incoming) { //std::cout << point << "\n"; //std::cout << counts[0] << " "; //std::cout << counts[1] << " "; //std::cout << counts[2] << " "; //std::cout << counts[3] << "\n"; //std::cout << incoming[0] << " "; //std::cout << incoming[1] << " "; //std::cout << incoming[2] << " "; //std::cout << incoming[3] << "\n"; //join any closing solid corners ActiveTail45* returnValue = 0; int returnCount = 0; for(int i = 0; i < 3; ++i) { //std::cout << i << "\n"; if(counts[i] == -1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < 4; ++j) { //std::cout << j << "\n"; if(counts[j]) { if(counts[j] == 1) { //std::cout << "case1: " << i << " " << j << "\n"; //if a figure is closed it will be written out by this function to output ActiveTail45::joinChains(point, tails[i], tails[j], true, output); counts[i] = 0; counts[j] = 0; tails[i] = 0; tails[j] = 0; } break; } } } } //find any pairs of incoming edges that need to create pair for leading solid //std::cout << "checking case2\n"; for(int i = 0; i < 3; ++i) { //std::cout << i << "\n"; if(incoming[i] == 1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < 4; ++j) { //std::cout << j << "\n"; if(incoming[j]) { if(incoming[j] == -1) { //std::cout << "case2: " << i << " " << j << "\n"; //std::cout << "creating active tail pair\n"; std::pair<ActiveTail45*, ActiveTail45*> tailPair = ActiveTail45::createActiveTail45sAsPair(point, true, 0, fractureHoles_ != 0); //tailPair.first->print(); //tailPair.second->print(); if(j == 3) { //vertical active tail becomes return value returnValue = tailPair.first; returnCount = 1; } else { Vertex45 vertex(point, i -1, incoming[i]); //std::cout << "new element " << j-1 << " " << -1 << "\n"; elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, -1), tailPair.first)); } //std::cout << "new element " << i-1 << " " << 1 << "\n"; elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, i -1, 1), tailPair.second)); incoming[i] = 0; incoming[j] = 0; } break; } } } } //find any active tail that needs to pass through to an incoming edge //we expect to find no more than two pass through //find pass through with solid on top //std::cout << "checking case 3\n"; for(int i = 0; i < 4; ++i) { //std::cout << i << "\n"; if(counts[i] != 0) { if(counts[i] == 1) { //std::cout << "fixed i\n"; for(int j = 3; j >= 0; --j) { if(incoming[j] != 0) { if(incoming[j] == 1) { //std::cout << "case3: " << i << " " << j << "\n"; //tails[i]->print(); //pass through solid on top tails[i]->pushPoint(point); //std::cout << "after push\n"; if(j == 3) { returnValue = tails[i]; returnCount = -1; } else { elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, incoming[j]), tails[i])); } tails[i] = 0; counts[i] = 0; incoming[j] = 0; } break; } } } break; } } //std::cout << "checking case 4\n"; //find pass through with solid on bottom for(int i = 3; i >= 0; --i) { if(counts[i] != 0) { if(counts[i] == -1) { for(int j = 0; j < 4; ++j) { if(incoming[j] != 0) { if(incoming[j] == -1) { //std::cout << "case4: " << i << " " << j << "\n"; //pass through solid on bottom tails[i]->pushPoint(point); if(j == 3) { returnValue = tails[i]; returnCount = 1; } else { //std::cout << "new element " << j-1 << " " << incoming[j] << "\n"; elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, incoming[j]), tails[i])); } tails[i] = 0; counts[i] = 0; incoming[j] = 0; } break; } } } break; } } //find the end of a hole or the beginning of a hole //find end of a hole for(int i = 0; i < 3; ++i) { if(counts[i] != 0) { for(int j = i+1; j < 4; ++j) { if(counts[j] != 0) { //std::cout << "case5: " << i << " " << j << "\n"; //we are ending a hole and may potentially close a figure and have to handle the hole returnValue = ActiveTail45::joinChains(point, tails[i], tails[j], false, output); tails[i] = 0; tails[j] = 0; counts[i] = 0; counts[j] = 0; break; } } break; } } //find beginning of a hole for(int i = 0; i < 3; ++i) { if(incoming[i] != 0) { for(int j = i+1; j < 4; ++j) { if(incoming[j] != 0) { //std::cout << "case6: " << i << " " << j << "\n"; //we are beginning a empty space ActiveTail45* holep = 0; if(counts[3] == 0) holep = tails[3]; std::pair<ActiveTail45*, ActiveTail45*> tailPair = ActiveTail45::createActiveTail45sAsPair(point, false, holep, fractureHoles_ != 0); if(j == 3) { returnValue = tailPair.first; returnCount = -1; } else { //std::cout << "new element " << j-1 << " " << incoming[j] << "\n"; elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, incoming[j]), tailPair.first)); } //std::cout << "new element " << i-1 << " " << incoming[i] << "\n"; elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, i -1, incoming[i]), tailPair.second)); incoming[i] = 0; incoming[j] = 0; break; } } break; } } //assert that tails, counts and incoming are all null return std::pair<int, ActiveTail45*>(returnCount, returnValue); } template <class cT, class iT> inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { //std::cout << "processEvent_\n"; justBefore_ = true; //collect up all elements from the tree that are at the y //values of events in the input queue //create vector of new elements to add into tree ActiveTail45* verticalTail = 0; int verticalCount = 0; iT currentIter = inputBegin; std::vector<iterator> elementIters; std::vector<std::pair<Vertex45, ActiveTail45*> > elements; while(currentIter != inputEnd && currentIter->pt.x() == x_) { //std::cout << "loop\n"; Unit currentY = (*currentIter).pt.y(); iterator iter = lookUp_(currentY); //int counts[4] = {0, 0, 0, 0}; Vertex45Count counts; ActiveTail45* tails[4] = {0, 0, 0, verticalTail}; //std::cout << "finding elements in tree\n"; while(iter != scanData_.end() && iter->first.evalAtX(x_) == currentY) { //std::cout << "loop2\n"; elementIters.push_back(iter); int index = iter->first.rise + 1; //std::cout << index << " " << iter->first.count << "\n"; counts[index] = iter->first.count; tails[index] = iter->second; ++iter; } //int incoming[4] = {0, 0, 0, 0}; Vertex45Count incoming; //std::cout << "aggregating\n"; do { //std::cout << "loop3\n"; Vertex45Compact currentVertex(*currentIter); incoming += currentVertex.count; ++currentIter; } while(currentIter != inputEnd && currentIter->pt.y() == currentY && currentIter->pt.x() == x_); //now counts and tails have the data from the left and //incoming has the data from the right at this point //cancel out any end points //std::cout << counts[0] << " "; //std::cout << counts[1] << " "; //std::cout << counts[2] << " "; //std::cout << counts[3] << "\n"; //std::cout << incoming[0] << " "; //std::cout << incoming[1] << " "; //std::cout << incoming[2] << " "; //std::cout << incoming[3] << "\n"; if(verticalTail) { counts[3] = -verticalCount; } incoming[3] *= -1; for(unsigned int i = 0; i < 4; ++i) incoming[i] += counts[i]; //std::cout << "calling processPoint_\n"; std::pair<int, ActiveTail45*> result = processPoint_(output, elements, Point(x_, currentY), counts, tails, incoming); verticalCount = result.first; verticalTail = result.second; //if(verticalTail) std::cout << "have vertical tail\n"; //std::cout << "verticalCount: " << verticalCount << "\n"; if(verticalTail && !verticalCount) { //we got a hole out of the point we just processed //iter is still at the next y element above the current y value in the tree //std::cout << "checking whether ot handle hole\n"; if(currentIter == inputEnd || currentIter->pt.x() != x_ || currentIter->pt.y() >= iter->first.evalAtX(x_)) { //std::cout << "handle hole here\n"; if(fractureHoles_) { //std::cout << "fracture hole here\n"; //we need to handle the hole now and not at the next input vertex ActiveTail45* at = iter->second; Point point(x_, iter->first.evalAtX(x_)); verticalTail->getOtherActiveTail()->pushPoint(point); iter->second = verticalTail->getOtherActiveTail(); at->pushPoint(point); verticalTail->join(at); delete at; delete verticalTail; verticalTail = 0; } else { //std::cout << "push hole onto list\n"; iter->second->addHole(verticalTail); verticalTail = 0; } } } } //std::cout << "erasing\n"; //erase all elements from the tree for(typename std::vector<iterator>::iterator iter = elementIters.begin(); iter != elementIters.end(); ++iter) { //std::cout << "erasing loop\n"; scanData_.erase(*iter); } //switch comparison tie breaking policy justBefore_ = false; //add new elements into tree //std::cout << "inserting\n"; for(typename std::vector<std::pair<Vertex45, ActiveTail45*> >::iterator iter = elements.begin(); iter != elements.end(); ++iter) { //std::cout << "inserting loop\n"; scanData_.insert(scanData_.end(), *iter); } //std::cout << "end processEvent\n"; return currentIter; } inline iterator lookUp_(Unit y){ //if just before then we need to look from 1 not -1 return scanData_.lower_bound(Vertex45(Point(x_, y), -1+2*justBefore_, 0)); } }; template <typename stream_type> static inline bool testPolygon45FormationRect(stream_type& stdcout) { stdcout << "testing polygon formation\n"; Polygon45Formation pf(true); std::vector<Polygon45> polys; std::vector<Vertex45> data; data.push_back(Vertex45(Point(0, 0), 0, 1)); data.push_back(Vertex45(Point(0, 0), 2, 1)); data.push_back(Vertex45(Point(0, 10), 2, -1)); data.push_back(Vertex45(Point(0, 10), 0, -1)); data.push_back(Vertex45(Point(10, 0), 0, -1)); data.push_back(Vertex45(Point(10, 0), 2, -1)); data.push_back(Vertex45(Point(10, 10), 2, 1)); data.push_back(Vertex45(Point(10, 10), 0, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } template <typename stream_type> static inline bool testPolygon45FormationP1(stream_type& stdcout) { stdcout << "testing polygon formation\n"; Polygon45Formation pf(true); std::vector<Polygon45> polys; std::vector<Vertex45> data; data.push_back(Vertex45(Point(0, 0), 1, 1)); data.push_back(Vertex45(Point(0, 0), 2, 1)); data.push_back(Vertex45(Point(0, 10), 2, -1)); data.push_back(Vertex45(Point(0, 10), 1, -1)); data.push_back(Vertex45(Point(10, 10), 1, -1)); data.push_back(Vertex45(Point(10, 10), 2, -1)); data.push_back(Vertex45(Point(10, 20), 2, 1)); data.push_back(Vertex45(Point(10, 20), 1, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } //polygon45set class template <typename stream_type> static inline bool testPolygon45FormationP2(stream_type& stdcout) { stdcout << "testing polygon formation\n"; Polygon45Formation pf(true); std::vector<Polygon45> polys; std::vector<Vertex45> data; data.push_back(Vertex45(Point(0, 0), 0, 1)); data.push_back(Vertex45(Point(0, 0), 1, -1)); data.push_back(Vertex45(Point(10, 0), 0, -1)); data.push_back(Vertex45(Point(10, 0), 1, 1)); data.push_back(Vertex45(Point(10, 10), 1, 1)); data.push_back(Vertex45(Point(10, 10), 0, -1)); data.push_back(Vertex45(Point(20, 10), 1, -1)); data.push_back(Vertex45(Point(20, 10), 0, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } //polygon45set class template <typename stream_type> static inline bool testPolygon45FormationStar1(stream_type& stdcout) { stdcout << "testing polygon formation\n"; Polygon45Formation pf(true); std::vector<Polygon45> polys; std::vector<Vertex45> data; // result == 0 8 -1 1 data.push_back(Vertex45(Point(0, 8), -1, 1)); // result == 0 8 1 -1 data.push_back(Vertex45(Point(0, 8), 1, -1)); // result == 4 0 1 1 data.push_back(Vertex45(Point(4, 0), 1, 1)); // result == 4 0 2 1 data.push_back(Vertex45(Point(4, 0), 2, 1)); // result == 4 4 2 -1 data.push_back(Vertex45(Point(4, 4), 2, -1)); // result == 4 4 -1 -1 data.push_back(Vertex45(Point(4, 4), -1, -1)); // result == 4 12 1 1 data.push_back(Vertex45(Point(4, 12), 1, 1)); // result == 4 12 2 1 data.push_back(Vertex45(Point(4, 12), 2, 1)); // result == 4 16 2 -1 data.push_back(Vertex45(Point(4, 16), 2, 1)); // result == 4 16 -1 -1 data.push_back(Vertex45(Point(4, 16), -1, -1)); // result == 6 2 1 -1 data.push_back(Vertex45(Point(6, 2), 1, -1)); // result == 6 14 -1 1 data.push_back(Vertex45(Point(6, 14), -1, 1)); // result == 6 2 -1 1 data.push_back(Vertex45(Point(6, 2), -1, 1)); // result == 6 14 1 -1 data.push_back(Vertex45(Point(6, 14), 1, -1)); // result == 8 0 -1 -1 data.push_back(Vertex45(Point(8, 0), -1, -1)); // result == 8 0 2 -1 data.push_back(Vertex45(Point(8, 0), 2, -1)); // result == 8 4 2 1 data.push_back(Vertex45(Point(8, 4), 2, 1)); // result == 8 4 1 1 data.push_back(Vertex45(Point(8, 4), 1, 1)); // result == 8 12 -1 -1 data.push_back(Vertex45(Point(8, 12), -1, -1)); // result == 8 12 2 -1 data.push_back(Vertex45(Point(8, 12), 2, -1)); // result == 8 16 2 1 data.push_back(Vertex45(Point(8, 16), 2, 1)); // result == 8 16 1 1 data.push_back(Vertex45(Point(8, 16), 1, 1)); // result == 12 8 1 -1 data.push_back(Vertex45(Point(12, 8), 1, -1)); // result == 12 8 -1 1 data.push_back(Vertex45(Point(12, 8), -1, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } template <typename stream_type> static inline bool testPolygon45FormationStar2(stream_type& stdcout) { stdcout << "testing polygon formation\n"; Polygon45Formation pf(true); std::vector<Polygon45> polys; Scan45 scan45; std::vector<Vertex45 > result; std::vector<Scan45Vertex> vertices; //is a Rectnagle(0, 0, 10, 10); Count2 count(1, 0); Count2 ncount(-1, 0); vertices.push_back(Scan45Vertex(Point(0,4), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(16,4), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(8,12), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); count = Count2(0, 1); ncount = count.invert(); vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(16,8), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); sortScan45Vector(vertices); stdcout << "scanning\n"; scan45.scan(result, vertices.begin(), vertices.end()); polygon_sort(result.begin(), result.end()); pf.scan(polys, result.begin(), result.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } template <typename stream_type> static inline bool testPolygon45FormationStarHole1(stream_type& stdcout) { stdcout << "testing polygon formation\n"; Polygon45Formation pf(true); std::vector<Polygon45> polys; std::vector<Vertex45> data; // result == 0 8 -1 1 data.push_back(Vertex45(Point(0, 8), -1, 1)); // result == 0 8 1 -1 data.push_back(Vertex45(Point(0, 8), 1, -1)); // result == 4 0 1 1 data.push_back(Vertex45(Point(4, 0), 1, 1)); // result == 4 0 2 1 data.push_back(Vertex45(Point(4, 0), 2, 1)); // result == 4 4 2 -1 data.push_back(Vertex45(Point(4, 4), 2, -1)); // result == 4 4 -1 -1 data.push_back(Vertex45(Point(4, 4), -1, -1)); // result == 4 12 1 1 data.push_back(Vertex45(Point(4, 12), 1, 1)); // result == 4 12 2 1 data.push_back(Vertex45(Point(4, 12), 2, 1)); // result == 4 16 2 -1 data.push_back(Vertex45(Point(4, 16), 2, 1)); // result == 4 16 -1 -1 data.push_back(Vertex45(Point(4, 16), -1, -1)); // result == 6 2 1 -1 data.push_back(Vertex45(Point(6, 2), 1, -1)); // result == 6 14 -1 1 data.push_back(Vertex45(Point(6, 14), -1, 1)); // result == 6 2 -1 1 data.push_back(Vertex45(Point(6, 2), -1, 1)); // result == 6 14 1 -1 data.push_back(Vertex45(Point(6, 14), 1, -1)); // result == 8 0 -1 -1 data.push_back(Vertex45(Point(8, 0), -1, -1)); // result == 8 0 2 -1 data.push_back(Vertex45(Point(8, 0), 2, -1)); // result == 8 4 2 1 data.push_back(Vertex45(Point(8, 4), 2, 1)); // result == 8 4 1 1 data.push_back(Vertex45(Point(8, 4), 1, 1)); // result == 8 12 -1 -1 data.push_back(Vertex45(Point(8, 12), -1, -1)); // result == 8 12 2 -1 data.push_back(Vertex45(Point(8, 12), 2, -1)); // result == 8 16 2 1 data.push_back(Vertex45(Point(8, 16), 2, 1)); // result == 8 16 1 1 data.push_back(Vertex45(Point(8, 16), 1, 1)); // result == 12 8 1 -1 data.push_back(Vertex45(Point(12, 8), 1, -1)); // result == 12 8 -1 1 data.push_back(Vertex45(Point(12, 8), -1, 1)); data.push_back(Vertex45(Point(6, 4), 1, -1)); data.push_back(Vertex45(Point(6, 4), 2, -1)); data.push_back(Vertex45(Point(6, 8), -1, 1)); data.push_back(Vertex45(Point(6, 8), 2, 1)); data.push_back(Vertex45(Point(8, 6), -1, -1)); data.push_back(Vertex45(Point(8, 6), 1, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } template <typename stream_type> static inline bool testPolygon45FormationStarHole2(stream_type& stdcout) { stdcout << "testing polygon formation\n"; Polygon45Formation pf(false); std::vector<Polygon45WithHoles> polys; std::vector<Vertex45> data; // result == 0 8 -1 1 data.push_back(Vertex45(Point(0, 8), -1, 1)); // result == 0 8 1 -1 data.push_back(Vertex45(Point(0, 8), 1, -1)); // result == 4 0 1 1 data.push_back(Vertex45(Point(4, 0), 1, 1)); // result == 4 0 2 1 data.push_back(Vertex45(Point(4, 0), 2, 1)); // result == 4 4 2 -1 data.push_back(Vertex45(Point(4, 4), 2, -1)); // result == 4 4 -1 -1 data.push_back(Vertex45(Point(4, 4), -1, -1)); // result == 4 12 1 1 data.push_back(Vertex45(Point(4, 12), 1, 1)); // result == 4 12 2 1 data.push_back(Vertex45(Point(4, 12), 2, 1)); // result == 4 16 2 -1 data.push_back(Vertex45(Point(4, 16), 2, 1)); // result == 4 16 -1 -1 data.push_back(Vertex45(Point(4, 16), -1, -1)); // result == 6 2 1 -1 data.push_back(Vertex45(Point(6, 2), 1, -1)); // result == 6 14 -1 1 data.push_back(Vertex45(Point(6, 14), -1, 1)); // result == 6 2 -1 1 data.push_back(Vertex45(Point(6, 2), -1, 1)); // result == 6 14 1 -1 data.push_back(Vertex45(Point(6, 14), 1, -1)); // result == 8 0 -1 -1 data.push_back(Vertex45(Point(8, 0), -1, -1)); // result == 8 0 2 -1 data.push_back(Vertex45(Point(8, 0), 2, -1)); // result == 8 4 2 1 data.push_back(Vertex45(Point(8, 4), 2, 1)); // result == 8 4 1 1 data.push_back(Vertex45(Point(8, 4), 1, 1)); // result == 8 12 -1 -1 data.push_back(Vertex45(Point(8, 12), -1, -1)); // result == 8 12 2 -1 data.push_back(Vertex45(Point(8, 12), 2, -1)); // result == 8 16 2 1 data.push_back(Vertex45(Point(8, 16), 2, 1)); // result == 8 16 1 1 data.push_back(Vertex45(Point(8, 16), 1, 1)); // result == 12 8 1 -1 data.push_back(Vertex45(Point(12, 8), 1, -1)); // result == 12 8 -1 1 data.push_back(Vertex45(Point(12, 8), -1, 1)); data.push_back(Vertex45(Point(6, 4), 1, -1)); data.push_back(Vertex45(Point(6, 4), 2, -1)); data.push_back(Vertex45(Point(6, 12), -1, 1)); data.push_back(Vertex45(Point(6, 12), 2, 1)); data.push_back(Vertex45(Point(10, 8), -1, -1)); data.push_back(Vertex45(Point(10, 8), 1, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } template <typename stream_type> static inline bool testPolygon45Formation(stream_type& stdcout) { stdcout << "testing polygon formation\n"; Polygon45Formation pf(false); std::vector<Polygon45WithHoles> polys; std::vector<Vertex45> data; data.push_back(Vertex45(Point(0, 0), 0, 1)); data.push_back(Vertex45(Point(0, 0), 2, 1)); data.push_back(Vertex45(Point(0, 100), 2, -1)); data.push_back(Vertex45(Point(0, 100), 0, -1)); data.push_back(Vertex45(Point(100, 0), 0, -1)); data.push_back(Vertex45(Point(100, 0), 2, -1)); data.push_back(Vertex45(Point(100, 100), 2, 1)); data.push_back(Vertex45(Point(100, 100), 0, 1)); data.push_back(Vertex45(Point(2, 2), 0, -1)); data.push_back(Vertex45(Point(2, 2), 2, -1)); data.push_back(Vertex45(Point(2, 10), 2, 1)); data.push_back(Vertex45(Point(2, 10), 0, 1)); data.push_back(Vertex45(Point(10, 2), 0, 1)); data.push_back(Vertex45(Point(10, 2), 2, 1)); data.push_back(Vertex45(Point(10, 10), 2, -1)); data.push_back(Vertex45(Point(10, 10), 0, -1)); data.push_back(Vertex45(Point(2, 12), 0, -1)); data.push_back(Vertex45(Point(2, 12), 2, -1)); data.push_back(Vertex45(Point(2, 22), 2, 1)); data.push_back(Vertex45(Point(2, 22), 0, 1)); data.push_back(Vertex45(Point(10, 12), 0, 1)); data.push_back(Vertex45(Point(10, 12), 2, 1)); data.push_back(Vertex45(Point(10, 22), 2, -1)); data.push_back(Vertex45(Point(10, 22), 0, -1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } class Polygon45Tiling { private: //definitions typedef std::map<Vertex45, ActiveTail45*, lessVertex45> Polygon45FormationData; typedef typename Polygon45FormationData::iterator iterator; typedef typename Polygon45FormationData::const_iterator const_iterator; //data Polygon45FormationData scanData_; Unit x_; int justBefore_; public: inline Polygon45Tiling() : scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false) { lessVertex45 lessElm(&x_, &justBefore_); scanData_ = Polygon45FormationData(lessElm); } inline Polygon45Tiling(const Polygon45Tiling& that) : scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false) { (*this) = that; } inline Polygon45Tiling& operator=(const Polygon45Tiling& that) { x_ = that.x_; justBefore_ = that.justBefore_; lessVertex45 lessElm(&x_, &justBefore_); scanData_ = Polygon45FormationData(lessElm); for(const_iterator itr = that.scanData_.begin(); itr != that.scanData_.end(); ++itr){ scanData_.insert(scanData_.end(), *itr); } return *this; } //cT is an output container of Polygon45 or Polygon45WithHoles //iT is an iterator over Vertex45 elements //inputBegin - inputEnd is a range of sorted iT that represents //one or more scanline stops worth of data template <class cT, class iT> void scan(cT& output, iT inputBegin, iT inputEnd) { //std::cout << "1\n"; while(inputBegin != inputEnd) { //std::cout << "2\n"; x_ = (*inputBegin).pt.x(); //std::cout << "SCAN FORMATION " << x_ << "\n"; //std::cout << "x_ = " << x_ << "\n"; //std::cout << "scan line size: " << scanData_.size() << "\n"; inputBegin = processEvent_(output, inputBegin, inputEnd); } } private: //functions inline void getVerticalPair_(std::pair<ActiveTail45*, ActiveTail45*>& verticalPair, iterator previter) { ActiveTail45* iterTail = (*previter).second; Point prevPoint(x_, previter->first.evalAtX(x_)); iterTail->pushPoint(prevPoint); std::pair<ActiveTail45*, ActiveTail45*> tailPair = ActiveTail45::createActiveTail45sAsPair(prevPoint, true, 0, false); verticalPair.first = iterTail; verticalPair.second = tailPair.first; (*previter).second = tailPair.second; } template <class cT, class cT2> inline std::pair<int, ActiveTail45*> processPoint_(cT& output, cT2& elements, std::pair<ActiveTail45*, ActiveTail45*>& verticalPair, iterator previter, Point point, Vertex45Count& counts, ActiveTail45** tails, Vertex45Count& incoming) { //std::cout << point << "\n"; //std::cout << counts[0] << " "; //std::cout << counts[1] << " "; //std::cout << counts[2] << " "; //std::cout << counts[3] << "\n"; //std::cout << incoming[0] << " "; //std::cout << incoming[1] << " "; //std::cout << incoming[2] << " "; //std::cout << incoming[3] << "\n"; //join any closing solid corners ActiveTail45* returnValue = 0; std::pair<ActiveTail45*, ActiveTail45*> verticalPairOut; verticalPairOut.first = 0; verticalPairOut.second = 0; int returnCount = 0; for(int i = 0; i < 3; ++i) { //std::cout << i << "\n"; if(counts[i] == -1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < 4; ++j) { //std::cout << j << "\n"; if(counts[j]) { if(counts[j] == 1) { //std::cout << "case1: " << i << " " << j << "\n"; //if a figure is closed it will be written out by this function to output ActiveTail45::joinChains(point, tails[i], tails[j], true, output); counts[i] = 0; counts[j] = 0; tails[i] = 0; tails[j] = 0; } break; } } } } //find any pairs of incoming edges that need to create pair for leading solid //std::cout << "checking case2\n"; for(int i = 0; i < 3; ++i) { //std::cout << i << "\n"; if(incoming[i] == 1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < 4; ++j) { //std::cout << j << "\n"; if(incoming[j]) { if(incoming[j] == -1) { //std::cout << "case2: " << i << " " << j << "\n"; //std::cout << "creating active tail pair\n"; std::pair<ActiveTail45*, ActiveTail45*> tailPair = ActiveTail45::createActiveTail45sAsPair(point, true, 0, false); //tailPair.first->print(); //tailPair.second->print(); if(j == 3) { //vertical active tail becomes return value returnValue = tailPair.first; returnCount = 1; } else { Vertex45 vertex(point, i -1, incoming[i]); //std::cout << "new element " << j-1 << " " << -1 << "\n"; elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, -1), tailPair.first)); } //std::cout << "new element " << i-1 << " " << 1 << "\n"; elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, i -1, 1), tailPair.second)); incoming[i] = 0; incoming[j] = 0; } break; } } } } //find any active tail that needs to pass through to an incoming edge //we expect to find no more than two pass through //find pass through with solid on top //std::cout << "checking case 3\n"; for(int i = 0; i < 4; ++i) { //std::cout << i << "\n"; if(counts[i] != 0) { if(counts[i] == 1) { //std::cout << "fixed i\n"; for(int j = 3; j >= 0; --j) { if(incoming[j] != 0) { if(incoming[j] == 1) { //std::cout << "case3: " << i << " " << j << "\n"; //tails[i]->print(); //pass through solid on top if(i != 3) tails[i]->pushPoint(point); //std::cout << "after push\n"; if(j == 3) { returnValue = tails[i]; returnCount = -1; } else { verticalPairOut.first = tails[i]; std::pair<ActiveTail45*, ActiveTail45*> tailPair = ActiveTail45::createActiveTail45sAsPair(point, true, 0, false); verticalPairOut.second = tailPair.first; elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, incoming[j]), tailPair.second)); } tails[i] = 0; counts[i] = 0; incoming[j] = 0; } break; } } } break; } } //std::cout << "checking case 4\n"; //find pass through with solid on bottom for(int i = 3; i >= 0; --i) { if(counts[i] != 0) { if(counts[i] == -1) { for(int j = 0; j < 4; ++j) { if(incoming[j] != 0) { if(incoming[j] == -1) { //std::cout << "case4: " << i << " " << j << "\n"; //pass through solid on bottom if(i == 3) { //std::cout << "new element " << j-1 << " " << incoming[j] << "\n"; if(j == 3) { returnValue = tails[i]; returnCount = 1; } else { tails[i]->pushPoint(point); elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, incoming[j]), tails[i])); } } else if(j == 3) { if(verticalPair.first == 0) { getVerticalPair_(verticalPair, previter); } ActiveTail45::joinChains(point, tails[i], verticalPair.first, true, output); returnValue = verticalPair.second; returnCount = 1; } else { if(verticalPair.first == 0) { getVerticalPair_(verticalPair, previter); } ActiveTail45::joinChains(point, tails[i], verticalPair.first, true, output); verticalPair.second->pushPoint(point); elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, incoming[j]), verticalPair.second)); } tails[i] = 0; counts[i] = 0; incoming[j] = 0; } break; } } } break; } } //find the end of a hole or the beginning of a hole //find end of a hole for(int i = 0; i < 3; ++i) { if(counts[i] != 0) { for(int j = i+1; j < 4; ++j) { if(counts[j] != 0) { //std::cout << "case5: " << i << " " << j << "\n"; //we are ending a hole and may potentially close a figure and have to handle the hole tails[i]->pushPoint(point); verticalPairOut.first = tails[i]; if(j == 3) { verticalPairOut.second = tails[j]; } else { if(verticalPair.first == 0) { getVerticalPair_(verticalPair, previter); } ActiveTail45::joinChains(point, tails[j], verticalPair.first, true, output); verticalPairOut.second = verticalPair.second; } tails[i] = 0; tails[j] = 0; counts[i] = 0; counts[j] = 0; break; } } break; } } //find beginning of a hole for(int i = 0; i < 3; ++i) { if(incoming[i] != 0) { for(int j = i+1; j < 4; ++j) { if(incoming[j] != 0) { //std::cout << "case6: " << i << " " << j << "\n"; //we are beginning a empty space if(verticalPair.first == 0) { getVerticalPair_(verticalPair, previter); } verticalPair.second->pushPoint(point); if(j == 3) { returnValue = verticalPair.first; returnCount = -1; } else { std::pair<ActiveTail45*, ActiveTail45*> tailPair = ActiveTail45::createActiveTail45sAsPair(point, true, 0, false); //std::cout << "new element " << j-1 << " " << incoming[j] << "\n"; elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, incoming[j]), tailPair.second)); verticalPairOut.second = tailPair.first; verticalPairOut.first = verticalPair.first; } //std::cout << "new element " << i-1 << " " << incoming[i] << "\n"; elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, i -1, incoming[i]), verticalPair.second)); incoming[i] = 0; incoming[j] = 0; break; } } break; } } verticalPair = verticalPairOut; //assert that verticalPair is either both null, or neither null //assert that returnValue is null if verticalPair is not null //assert that tails, counts and incoming are all null return std::pair<int, ActiveTail45*>(returnCount, returnValue); } template <class cT, class iT> inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { //std::cout << "processEvent_\n"; justBefore_ = true; //collect up all elements from the tree that are at the y //values of events in the input queue //create vector of new elements to add into tree ActiveTail45* verticalTail = 0; std::pair<ActiveTail45*, ActiveTail45*> verticalPair; verticalPair.first = 0; verticalPair.second = 0; int verticalCount = 0; iT currentIter = inputBegin; std::vector<iterator> elementIters; std::vector<std::pair<Vertex45, ActiveTail45*> > elements; while(currentIter != inputEnd && currentIter->pt.x() == x_) { //std::cout << "loop\n"; Unit currentY = (*currentIter).pt.y(); iterator iter = lookUp_(currentY); //int counts[4] = {0, 0, 0, 0}; Vertex45Count counts; ActiveTail45* tails[4] = {0, 0, 0, verticalTail}; //std::cout << "finding elements in tree\n"; iterator previter = iter; if(previter != scanData_.end() && previter->first.evalAtX(x_) >= currentY && previter != scanData_.begin()) --previter; while(iter != scanData_.end() && iter->first.evalAtX(x_) == currentY) { //std::cout << "loop2\n"; elementIters.push_back(iter); int index = iter->first.rise + 1; //std::cout << index << " " << iter->first.count << "\n"; counts[index] = iter->first.count; tails[index] = iter->second; ++iter; } //int incoming[4] = {0, 0, 0, 0}; Vertex45Count incoming; //std::cout << "aggregating\n"; do { //std::cout << "loop3\n"; Vertex45Compact currentVertex(*currentIter); incoming += currentVertex.count; ++currentIter; } while(currentIter != inputEnd && currentIter->pt.y() == currentY && currentIter->pt.x() == x_); //now counts and tails have the data from the left and //incoming has the data from the right at this point //cancel out any end points //std::cout << counts[0] << " "; //std::cout << counts[1] << " "; //std::cout << counts[2] << " "; //std::cout << counts[3] << "\n"; //std::cout << incoming[0] << " "; //std::cout << incoming[1] << " "; //std::cout << incoming[2] << " "; //std::cout << incoming[3] << "\n"; if(verticalTail) { counts[3] = -verticalCount; } incoming[3] *= -1; for(unsigned int i = 0; i < 4; ++i) incoming[i] += counts[i]; //std::cout << "calling processPoint_\n"; std::pair<int, ActiveTail45*> result = processPoint_(output, elements, verticalPair, previter, Point(x_, currentY), counts, tails, incoming); verticalCount = result.first; verticalTail = result.second; if(verticalPair.first != 0 && iter != scanData_.end() && (currentIter == inputEnd || currentIter->pt.x() != x_ || currentIter->pt.y() > (*iter).first.evalAtX(x_))) { //splice vertical pair into edge above ActiveTail45* tailabove = (*iter).second; Point point(x_, (*iter).first.evalAtX(x_)); verticalPair.second->pushPoint(point); ActiveTail45::joinChains(point, tailabove, verticalPair.first, true, output); (*iter).second = verticalPair.second; verticalPair.first = 0; verticalPair.second = 0; } } //std::cout << "erasing\n"; //erase all elements from the tree for(typename std::vector<iterator>::iterator iter = elementIters.begin(); iter != elementIters.end(); ++iter) { //std::cout << "erasing loop\n"; scanData_.erase(*iter); } //switch comparison tie breaking policy justBefore_ = false; //add new elements into tree //std::cout << "inserting\n"; for(typename std::vector<std::pair<Vertex45, ActiveTail45*> >::iterator iter = elements.begin(); iter != elements.end(); ++iter) { //std::cout << "inserting loop\n"; scanData_.insert(scanData_.end(), *iter); } //std::cout << "end processEvent\n"; return currentIter; } inline iterator lookUp_(Unit y){ //if just before then we need to look from 1 not -1 return scanData_.lower_bound(Vertex45(Point(x_, y), -1+2*justBefore_, 0)); } }; template <typename stream_type> static inline bool testPolygon45TilingRect(stream_type& stdcout) { stdcout << "testing polygon tiling\n"; Polygon45Tiling pf; std::vector<Polygon45> polys; std::vector<Vertex45> data; data.push_back(Vertex45(Point(0, 0), 0, 1)); data.push_back(Vertex45(Point(0, 0), 2, 1)); data.push_back(Vertex45(Point(0, 10), 2, -1)); data.push_back(Vertex45(Point(0, 10), 0, -1)); data.push_back(Vertex45(Point(10, 0), 0, -1)); data.push_back(Vertex45(Point(10, 0), 2, -1)); data.push_back(Vertex45(Point(10, 10), 2, 1)); data.push_back(Vertex45(Point(10, 10), 0, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; } template <typename stream_type> static inline bool testPolygon45TilingP1(stream_type& stdcout) { stdcout << "testing polygon tiling\n"; Polygon45Tiling pf; std::vector<Polygon45> polys; std::vector<Vertex45> data; data.push_back(Vertex45(Point(0, 0), 1, 1)); data.push_back(Vertex45(Point(0, 0), 2, 1)); data.push_back(Vertex45(Point(0, 10), 2, -1)); data.push_back(Vertex45(Point(0, 10), 1, -1)); data.push_back(Vertex45(Point(10, 10), 1, -1)); data.push_back(Vertex45(Point(10, 10), 2, -1)); data.push_back(Vertex45(Point(10, 20), 2, 1)); data.push_back(Vertex45(Point(10, 20), 1, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; } template <typename stream_type> static inline bool testPolygon45TilingP2(stream_type& stdcout) { stdcout << "testing polygon tiling\n"; Polygon45Tiling pf; std::vector<Polygon45> polys; std::vector<Vertex45> data; data.push_back(Vertex45(Point(0, 0), 0, 1)); data.push_back(Vertex45(Point(0, 0), 1, -1)); data.push_back(Vertex45(Point(10, 0), 0, -1)); data.push_back(Vertex45(Point(10, 0), 1, 1)); data.push_back(Vertex45(Point(10, 10), 1, 1)); data.push_back(Vertex45(Point(10, 10), 0, -1)); data.push_back(Vertex45(Point(20, 10), 1, -1)); data.push_back(Vertex45(Point(20, 10), 0, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; } template <typename stream_type> static inline bool testPolygon45TilingP3(stream_type& stdcout) { stdcout << "testing polygon tiling\n"; Polygon45Tiling pf; std::vector<Polygon45> polys; std::vector<Vertex45> data; data.push_back(Vertex45(Point(0, 0), 0, 1)); data.push_back(Vertex45(Point(0, 0), 2, 1)); data.push_back(Vertex45(Point(0, 10), 2, -1)); data.push_back(Vertex45(Point(0, 10), 0, -1)); data.push_back(Vertex45(Point(20, 0), 0, -1)); data.push_back(Vertex45(Point(20, 0), 2, -1)); data.push_back(Vertex45(Point(10, 10), 1, -1)); data.push_back(Vertex45(Point(10, 10), 0, 1)); data.push_back(Vertex45(Point(20, 20), 1, 1)); data.push_back(Vertex45(Point(20, 20), 2, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; } template <typename stream_type> static inline bool testPolygon45TilingP4(stream_type& stdcout) { stdcout << "testing polygon tiling p4\n"; Polygon45Tiling pf; std::vector<Polygon45> polys; std::vector<Vertex45> data; data.push_back(Vertex45(Point(0, 0), 0, 1)); data.push_back(Vertex45(Point(0, 0), 2, 1)); data.push_back(Vertex45(Point(0, 10), 2, -1)); data.push_back(Vertex45(Point(0, 10), 0, -1)); data.push_back(Vertex45(Point(10, 0), -1, 1)); data.push_back(Vertex45(Point(10, 0), 0, -1)); data.push_back(Vertex45(Point(20, 10), 2, 1)); data.push_back(Vertex45(Point(20, 10), 0, 1)); data.push_back(Vertex45(Point(20, -10), -1, -1)); data.push_back(Vertex45(Point(20, -10), 2, -1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; } template <typename stream_type> static inline bool testPolygon45TilingP5(stream_type& stdcout) { stdcout << "testing polygon tiling P5\n"; Polygon45Tiling pf; std::vector<Polygon45> polys; std::vector<Vertex45> data; data.push_back(Vertex45(Point(0, 0), 0, 1)); data.push_back(Vertex45(Point(0, 0), 2, 1)); data.push_back(Vertex45(Point(0, 10), 2, -1)); data.push_back(Vertex45(Point(0, 10), 0, -1)); data.push_back(Vertex45(Point(10, 0), 0, -1)); data.push_back(Vertex45(Point(10, 0), 2, -1)); data.push_back(Vertex45(Point(10, 10), 2, 1)); data.push_back(Vertex45(Point(10, 10), 0, 1)); data.push_back(Vertex45(Point(1, 1), 0, -1)); data.push_back(Vertex45(Point(1, 1), 1, 1)); data.push_back(Vertex45(Point(2, 1), 0, 1)); data.push_back(Vertex45(Point(2, 1), 1, -1)); data.push_back(Vertex45(Point(2, 2), 1, -1)); data.push_back(Vertex45(Point(2, 2), 0, 1)); data.push_back(Vertex45(Point(3, 2), 1, 1)); data.push_back(Vertex45(Point(3, 2), 0, -1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; } template <typename stream_type> static inline bool testPolygon45TilingP6(stream_type& stdcout) { stdcout << "testing polygon tiling P6\n"; Polygon45Tiling pf; std::vector<Polygon45> polys; std::vector<Vertex45> data; data.push_back(Vertex45(Point(0, 0), 0, 1)); data.push_back(Vertex45(Point(0, 0), 2, 1)); data.push_back(Vertex45(Point(0, 10), 2, -1)); data.push_back(Vertex45(Point(0, 10), 0, -1)); data.push_back(Vertex45(Point(10, 0), 0, -1)); data.push_back(Vertex45(Point(10, 0), 2, -1)); data.push_back(Vertex45(Point(10, 10), 2, 1)); data.push_back(Vertex45(Point(10, 10), 0, 1)); data.push_back(Vertex45(Point(1, 1), 0, -1)); data.push_back(Vertex45(Point(1, 1), 2, -1)); data.push_back(Vertex45(Point(1, 2), 2, 1)); data.push_back(Vertex45(Point(1, 2), 0, 1)); data.push_back(Vertex45(Point(2, 1), 0, 1)); data.push_back(Vertex45(Point(2, 1), 2, 1)); data.push_back(Vertex45(Point(2, 2), 2, -1)); data.push_back(Vertex45(Point(2, 2), 0, -1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; } template <typename stream_type> static inline bool testPolygon45TilingStar1(stream_type& stdcout) { stdcout << "testing polygon tiling star1\n"; Polygon45Tiling pf; std::vector<Polygon45> polys; std::vector<Vertex45> data; // result == 0 8 -1 1 data.push_back(Vertex45(Point(0, 8), -1, 1)); // result == 0 8 1 -1 data.push_back(Vertex45(Point(0, 8), 1, -1)); // result == 4 0 1 1 data.push_back(Vertex45(Point(4, 0), 1, 1)); // result == 4 0 2 1 data.push_back(Vertex45(Point(4, 0), 2, 1)); // result == 4 4 2 -1 data.push_back(Vertex45(Point(4, 4), 2, -1)); // result == 4 4 -1 -1 data.push_back(Vertex45(Point(4, 4), -1, -1)); // result == 4 12 1 1 data.push_back(Vertex45(Point(4, 12), 1, 1)); // result == 4 12 2 1 data.push_back(Vertex45(Point(4, 12), 2, 1)); // result == 4 16 2 -1 data.push_back(Vertex45(Point(4, 16), 2, 1)); // result == 4 16 -1 -1 data.push_back(Vertex45(Point(4, 16), -1, -1)); // result == 6 2 1 -1 data.push_back(Vertex45(Point(6, 2), 1, -1)); // result == 6 14 -1 1 data.push_back(Vertex45(Point(6, 14), -1, 1)); // result == 6 2 -1 1 data.push_back(Vertex45(Point(6, 2), -1, 1)); // result == 6 14 1 -1 data.push_back(Vertex45(Point(6, 14), 1, -1)); // result == 8 0 -1 -1 data.push_back(Vertex45(Point(8, 0), -1, -1)); // result == 8 0 2 -1 data.push_back(Vertex45(Point(8, 0), 2, -1)); // result == 8 4 2 1 data.push_back(Vertex45(Point(8, 4), 2, 1)); // result == 8 4 1 1 data.push_back(Vertex45(Point(8, 4), 1, 1)); // result == 8 12 -1 -1 data.push_back(Vertex45(Point(8, 12), -1, -1)); // result == 8 12 2 -1 data.push_back(Vertex45(Point(8, 12), 2, -1)); // result == 8 16 2 1 data.push_back(Vertex45(Point(8, 16), 2, 1)); // result == 8 16 1 1 data.push_back(Vertex45(Point(8, 16), 1, 1)); // result == 12 8 1 -1 data.push_back(Vertex45(Point(12, 8), 1, -1)); // result == 12 8 -1 1 data.push_back(Vertex45(Point(12, 8), -1, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; } template <typename stream_type> static inline bool testPolygon45TilingStar2(stream_type& stdcout) { stdcout << "testing polygon tiling\n"; Polygon45Tiling pf; std::vector<Polygon45> polys; Scan45 scan45; std::vector<Vertex45 > result; std::vector<Scan45Vertex> vertices; //is a Rectnagle(0, 0, 10, 10); Count2 count(1, 0); Count2 ncount(-1, 0); vertices.push_back(Scan45Vertex(Point(0,4), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(16,4), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(8,12), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); count = Count2(0, 1); ncount = count.invert(); vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(16,8), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); sortScan45Vector(vertices); stdcout << "scanning\n"; scan45.scan(result, vertices.begin(), vertices.end()); polygon_sort(result.begin(), result.end()); pf.scan(polys, result.begin(), result.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; } template <typename stream_type> static inline bool testPolygon45TilingStarHole1(stream_type& stdcout) { stdcout << "testing polygon tiling star hole 1\n"; Polygon45Tiling pf; std::vector<Polygon45> polys; std::vector<Vertex45> data; // result == 0 8 -1 1 data.push_back(Vertex45(Point(0, 8), -1, 1)); // result == 0 8 1 -1 data.push_back(Vertex45(Point(0, 8), 1, -1)); // result == 4 0 1 1 data.push_back(Vertex45(Point(4, 0), 1, 1)); // result == 4 0 2 1 data.push_back(Vertex45(Point(4, 0), 2, 1)); // result == 4 4 2 -1 data.push_back(Vertex45(Point(4, 4), 2, -1)); // result == 4 4 -1 -1 data.push_back(Vertex45(Point(4, 4), -1, -1)); // result == 4 12 1 1 data.push_back(Vertex45(Point(4, 12), 1, 1)); // result == 4 12 2 1 data.push_back(Vertex45(Point(4, 12), 2, 1)); // result == 4 16 2 -1 data.push_back(Vertex45(Point(4, 16), 2, 1)); // result == 4 16 -1 -1 data.push_back(Vertex45(Point(4, 16), -1, -1)); // result == 6 2 1 -1 data.push_back(Vertex45(Point(6, 2), 1, -1)); // result == 6 14 -1 1 data.push_back(Vertex45(Point(6, 14), -1, 1)); // result == 6 2 -1 1 data.push_back(Vertex45(Point(6, 2), -1, 1)); // result == 6 14 1 -1 data.push_back(Vertex45(Point(6, 14), 1, -1)); // result == 8 0 -1 -1 data.push_back(Vertex45(Point(8, 0), -1, -1)); // result == 8 0 2 -1 data.push_back(Vertex45(Point(8, 0), 2, -1)); // result == 8 4 2 1 data.push_back(Vertex45(Point(8, 4), 2, 1)); // result == 8 4 1 1 data.push_back(Vertex45(Point(8, 4), 1, 1)); // result == 8 12 -1 -1 data.push_back(Vertex45(Point(8, 12), -1, -1)); // result == 8 12 2 -1 data.push_back(Vertex45(Point(8, 12), 2, -1)); // result == 8 16 2 1 data.push_back(Vertex45(Point(8, 16), 2, 1)); // result == 8 16 1 1 data.push_back(Vertex45(Point(8, 16), 1, 1)); // result == 12 8 1 -1 data.push_back(Vertex45(Point(12, 8), 1, -1)); // result == 12 8 -1 1 data.push_back(Vertex45(Point(12, 8), -1, 1)); data.push_back(Vertex45(Point(6, 4), 1, -1)); data.push_back(Vertex45(Point(6, 4), 2, -1)); data.push_back(Vertex45(Point(6, 8), -1, 1)); data.push_back(Vertex45(Point(6, 8), 2, 1)); data.push_back(Vertex45(Point(8, 6), -1, -1)); data.push_back(Vertex45(Point(8, 6), 1, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; } template <typename stream_type> static inline bool testPolygon45TilingStarHole2(stream_type& stdcout) { stdcout << "testing polygon tiling star hole 2\n"; Polygon45Tiling pf; std::vector<Polygon45WithHoles> polys; std::vector<Vertex45> data; // result == 0 8 -1 1 data.push_back(Vertex45(Point(0, 8), -1, 1)); // result == 0 8 1 -1 data.push_back(Vertex45(Point(0, 8), 1, -1)); // result == 4 0 1 1 data.push_back(Vertex45(Point(4, 0), 1, 1)); // result == 4 0 2 1 data.push_back(Vertex45(Point(4, 0), 2, 1)); // result == 4 4 2 -1 data.push_back(Vertex45(Point(4, 4), 2, -1)); // result == 4 4 -1 -1 data.push_back(Vertex45(Point(4, 4), -1, -1)); // result == 4 12 1 1 data.push_back(Vertex45(Point(4, 12), 1, 1)); // result == 4 12 2 1 data.push_back(Vertex45(Point(4, 12), 2, 1)); // result == 4 16 2 -1 data.push_back(Vertex45(Point(4, 16), 2, 1)); // result == 4 16 -1 -1 data.push_back(Vertex45(Point(4, 16), -1, -1)); // result == 6 2 1 -1 data.push_back(Vertex45(Point(6, 2), 1, -1)); // result == 6 14 -1 1 data.push_back(Vertex45(Point(6, 14), -1, 1)); // result == 6 2 -1 1 data.push_back(Vertex45(Point(6, 2), -1, 1)); // result == 6 14 1 -1 data.push_back(Vertex45(Point(6, 14), 1, -1)); // result == 8 0 -1 -1 data.push_back(Vertex45(Point(8, 0), -1, -1)); // result == 8 0 2 -1 data.push_back(Vertex45(Point(8, 0), 2, -1)); // result == 8 4 2 1 data.push_back(Vertex45(Point(8, 4), 2, 1)); // result == 8 4 1 1 data.push_back(Vertex45(Point(8, 4), 1, 1)); // result == 8 12 -1 -1 data.push_back(Vertex45(Point(8, 12), -1, -1)); // result == 8 12 2 -1 data.push_back(Vertex45(Point(8, 12), 2, -1)); // result == 8 16 2 1 data.push_back(Vertex45(Point(8, 16), 2, 1)); // result == 8 16 1 1 data.push_back(Vertex45(Point(8, 16), 1, 1)); // result == 12 8 1 -1 data.push_back(Vertex45(Point(12, 8), 1, -1)); // result == 12 8 -1 1 data.push_back(Vertex45(Point(12, 8), -1, 1)); data.push_back(Vertex45(Point(6, 4), 1, -1)); data.push_back(Vertex45(Point(6, 4), 2, -1)); data.push_back(Vertex45(Point(6, 12), -1, 1)); data.push_back(Vertex45(Point(6, 12), 2, 1)); data.push_back(Vertex45(Point(10, 8), -1, -1)); data.push_back(Vertex45(Point(10, 8), 1, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; } template <typename stream_type> static inline bool testPolygon45Tiling(stream_type& stdcout) { stdcout << "testing polygon tiling\n"; Polygon45Tiling pf; std::vector<Polygon45WithHoles> polys; std::vector<Vertex45> data; data.push_back(Vertex45(Point(0, 0), 0, 1)); data.push_back(Vertex45(Point(0, 0), 2, 1)); data.push_back(Vertex45(Point(0, 100), 2, -1)); data.push_back(Vertex45(Point(0, 100), 0, -1)); data.push_back(Vertex45(Point(100, 0), 0, -1)); data.push_back(Vertex45(Point(100, 0), 2, -1)); data.push_back(Vertex45(Point(100, 100), 2, 1)); data.push_back(Vertex45(Point(100, 100), 0, 1)); data.push_back(Vertex45(Point(2, 2), 0, -1)); data.push_back(Vertex45(Point(2, 2), 2, -1)); data.push_back(Vertex45(Point(2, 10), 2, 1)); data.push_back(Vertex45(Point(2, 10), 0, 1)); data.push_back(Vertex45(Point(10, 2), 0, 1)); data.push_back(Vertex45(Point(10, 2), 2, 1)); data.push_back(Vertex45(Point(10, 10), 2, -1)); data.push_back(Vertex45(Point(10, 10), 0, -1)); data.push_back(Vertex45(Point(2, 12), 0, -1)); data.push_back(Vertex45(Point(2, 12), 2, -1)); data.push_back(Vertex45(Point(2, 22), 2, 1)); data.push_back(Vertex45(Point(2, 22), 0, 1)); data.push_back(Vertex45(Point(10, 12), 0, 1)); data.push_back(Vertex45(Point(10, 12), 2, 1)); data.push_back(Vertex45(Point(10, 22), 2, -1)); data.push_back(Vertex45(Point(10, 22), 0, -1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; } }; template <typename Unit> class PolyLine45HoleData { public: typedef typename polygon_45_formation<Unit>::ActiveTail45 ActiveTail45; typedef typename ActiveTail45::iterator iterator; typedef polygon_45_concept geometry_type; typedef Unit coordinate_type; typedef point_data<Unit> Point; typedef Point point_type; // typedef iterator_points_to_compact<iterator, Point> compact_iterator_type; typedef iterator iterator_type; typedef typename coordinate_traits<Unit>::area_type area_type; inline PolyLine45HoleData() : p_(0) {} inline PolyLine45HoleData(ActiveTail45* p) : p_(p) {} //use default copy and assign inline iterator begin() const { return p_->getTail()->begin(); } inline iterator end() const { return p_->getTail()->end(); } inline std::size_t size() const { return 0; } private: ActiveTail45* p_; }; template <typename Unit> class PolyLine45PolygonData { public: typedef typename polygon_45_formation<Unit>::ActiveTail45 ActiveTail45; typedef typename ActiveTail45::iterator iterator; typedef PolyLine45HoleData<Unit> holeType; typedef polygon_45_with_holes_concept geometry_type; typedef Unit coordinate_type; typedef point_data<Unit> Point; typedef Point point_type; // typedef iterator_points_to_compact<iterator, Point> compact_iterator_type; typedef iterator iterator_type; typedef holeType hole_type; typedef typename coordinate_traits<Unit>::area_type area_type; class iteratorHoles { private: typename ActiveTail45::iteratorHoles itr_; public: typedef PolyLine45HoleData<Unit> holeType; typedef holeType value_type; typedef std::forward_iterator_tag iterator_category; typedef std::ptrdiff_t difference_type; typedef const value_type* pointer; //immutable typedef const value_type& reference; //immutable inline iteratorHoles() : itr_() {} inline iteratorHoles(typename ActiveTail45::iteratorHoles itr) : itr_(itr) {} inline iteratorHoles(const iteratorHoles& that) : itr_(that.itr_) {} inline iteratorHoles& operator=(const iteratorHoles& that) { itr_ = that.itr_; return *this; } inline bool operator==(const iteratorHoles& that) { return itr_ == that.itr_; } inline bool operator!=(const iteratorHoles& that) { return itr_ != that.itr_; } inline iteratorHoles& operator++() { ++itr_; return *this; } inline const iteratorHoles operator++(int) { iteratorHoles tmp = *this; ++(*this); return tmp; } inline holeType operator*() { return *itr_; } }; typedef iteratorHoles iterator_holes_type; inline PolyLine45PolygonData() : p_(0) {} inline PolyLine45PolygonData(ActiveTail45* p) : p_(p) {} //use default copy and assign inline iterator begin() const { return p_->getTail()->begin(); } inline iterator end() const { return p_->getTail()->end(); } inline iteratorHoles begin_holes() const { return iteratorHoles(p_->getHoles().begin()); } inline iteratorHoles end_holes() const { return iteratorHoles(p_->getHoles().end()); } inline ActiveTail45* yield() { return p_; } //stub out these four required functions that will not be used but are needed for the interface inline std::size_t size_holes() const { return 0; } inline std::size_t size() const { return 0; } private: ActiveTail45* p_; }; template <typename T> struct PolyLineByConcept<T, polygon_45_with_holes_concept> { typedef PolyLine45PolygonData<T> type; }; template <typename T> struct PolyLineByConcept<T, polygon_with_holes_concept> { typedef PolyLine45PolygonData<T> type; }; template <typename T> struct PolyLineByConcept<T, polygon_45_concept> { typedef PolyLine45HoleData<T> type; }; template <typename T> struct PolyLineByConcept<T, polygon_concept> { typedef PolyLine45HoleData<T> type; }; template <typename T> struct geometry_concept<PolyLine45PolygonData<T> > { typedef polygon_45_with_holes_concept type; }; template <typename T> struct geometry_concept<PolyLine45HoleData<T> > { typedef polygon_45_concept type; }; } } #endif detail/minkowski.hpp 0000644 00000011517 15125572616 0010551 0 ustar 00 /* 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). */ namespace boost { namespace polygon { namespace detail { template <typename coordinate_type> struct minkowski_offset { typedef point_data<coordinate_type> point; typedef polygon_set_data<coordinate_type> polygon_set; typedef polygon_with_holes_data<coordinate_type> polygon; typedef std::pair<point, point> edge; static void convolve_two_segments(std::vector<point>& figure, const edge& a, const edge& b) { figure.clear(); figure.push_back(point(a.first)); figure.push_back(point(a.first)); figure.push_back(point(a.second)); figure.push_back(point(a.second)); convolve(figure[0], b.second); convolve(figure[1], b.first); convolve(figure[2], b.first); convolve(figure[3], b.second); } template <typename itrT1, typename itrT2> static void convolve_two_point_sequences(polygon_set& result, itrT1 ab, itrT1 ae, itrT2 bb, itrT2 be) { if(ab == ae || bb == be) return; point first_a = *ab; point prev_a = *ab; std::vector<point> vec; polygon poly; ++ab; for( ; ab != ae; ++ab) { point first_b = *bb; point prev_b = *bb; itrT2 tmpb = bb; ++tmpb; for( ; tmpb != be; ++tmpb) { convolve_two_segments(vec, std::make_pair(prev_b, *tmpb), std::make_pair(prev_a, *ab)); set_points(poly, vec.begin(), vec.end()); result.insert(poly); prev_b = *tmpb; } prev_a = *ab; } } template <typename itrT> static void convolve_point_sequence_with_polygons(polygon_set& result, itrT b, itrT e, const std::vector<polygon>& polygons) { for(std::size_t i = 0; i < polygons.size(); ++i) { convolve_two_point_sequences(result, b, e, begin_points(polygons[i]), end_points(polygons[i])); for(typename polygon_with_holes_traits<polygon>::iterator_holes_type itrh = begin_holes(polygons[i]); itrh != end_holes(polygons[i]); ++itrh) { convolve_two_point_sequences(result, b, e, begin_points(*itrh), end_points(*itrh)); } } } static void convolve_two_polygon_sets(polygon_set& result, const polygon_set& a, const polygon_set& b) { result.clear(); std::vector<polygon> a_polygons; std::vector<polygon> b_polygons; a.get(a_polygons); b.get(b_polygons); for(std::size_t ai = 0; ai < a_polygons.size(); ++ai) { convolve_point_sequence_with_polygons(result, begin_points(a_polygons[ai]), end_points(a_polygons[ai]), b_polygons); for(typename polygon_with_holes_traits<polygon>::iterator_holes_type itrh = begin_holes(a_polygons[ai]); itrh != end_holes(a_polygons[ai]); ++itrh) { convolve_point_sequence_with_polygons(result, begin_points(*itrh), end_points(*itrh), b_polygons); } for(std::size_t bi = 0; bi < b_polygons.size(); ++bi) { polygon tmp_poly = a_polygons[ai]; result.insert(convolve(tmp_poly, *(begin_points(b_polygons[bi])))); tmp_poly = b_polygons[bi]; result.insert(convolve(tmp_poly, *(begin_points(a_polygons[ai])))); } } } }; } template<typename T> inline polygon_set_data<T>& polygon_set_data<T>::resize(coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments) { using namespace ::boost::polygon::operators; if(!corner_fill_arc) { if(resizing < 0) return shrink(-resizing); if(resizing > 0) return bloat(resizing); return *this; } if(resizing == 0) return *this; if(empty()) return *this; if(num_circle_segments < 3) num_circle_segments = 4; rectangle_data<coordinate_type> rect; extents(rect); if(resizing < 0) { ::boost::polygon::bloat(rect, 10); (*this) = rect - (*this); //invert } //make_arc(std::vector<point_data< T> >& return_points, //point_data< double> start, point_data< double> end, //point_data< double> center, double r, unsigned int num_circle_segments) std::vector<point_data<coordinate_type> > circle; point_data<double> center(0.0, 0.0), start(0.0, (double)resizing); make_arc(circle, start, start, center, std::abs((double)resizing), num_circle_segments); polygon_data<coordinate_type> poly; set_points(poly, circle.begin(), circle.end()); polygon_set_data<coordinate_type> offset_set; offset_set += poly; polygon_set_data<coordinate_type> result; detail::minkowski_offset<coordinate_type>::convolve_two_polygon_sets (result, *this, offset_set); if(resizing < 0) { result = result & rect;//eliminate overhang result = result ^ rect;//invert } *this = result; return *this; } }} detail/polygon_simplify.hpp 0000644 00000007542 15125572616 0012144 0 ustar 00 // 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 detail/max_cover.hpp 0000644 00000026564 15125572616 0010531 0 ustar 00 /* 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_MAX_COVER_HPP #define BOOST_POLYGON_MAX_COVER_HPP namespace boost { namespace polygon{ template <typename Unit> struct MaxCover { typedef interval_data<Unit> Interval; typedef rectangle_data<Unit> Rectangle; class Node { private: std::vector<Node*> children_; std::set<Interval> tracedPaths_; public: Rectangle rect; Node() : children_(), tracedPaths_(), rect() {} Node(const Rectangle rectIn) : children_(), tracedPaths_(), rect(rectIn) {} typedef typename std::vector<Node*>::iterator iterator; inline iterator begin() { return children_.begin(); } inline iterator end() { return children_.end(); } inline void add(Node* child) { children_.push_back(child); } inline bool tracedPath(const Interval& ivl) const { return tracedPaths_.find(ivl) != tracedPaths_.end(); } inline void addPath(const Interval& ivl) { tracedPaths_.insert(tracedPaths_.end(), ivl); } }; typedef std::pair<std::pair<Unit, Interval>, Node* > EdgeAssociation; class lessEdgeAssociation { public: typedef const EdgeAssociation& first_argument_type; typedef const EdgeAssociation& second_argument_type; typedef bool result_type; inline lessEdgeAssociation() {} inline bool operator () (const EdgeAssociation& elem1, const EdgeAssociation& elem2) const { if(elem1.first.first < elem2.first.first) return true; if(elem1.first.first > elem2.first.first) return false; return elem1.first.second < elem2.first.second; } }; template <class cT> static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient) { Interval rectIvl = node->rect.get(orient); if(node->tracedPath(rectIvl)) { return; } node->addPath(rectIvl); if(node->begin() == node->end()) { //std::cout << "WRITE OUT 3: " << node->rect << std::endl; outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(node->rect)); return; } bool writeOut = true; for(typename Node::iterator itr = node->begin(); itr != node->end(); ++itr) { getMaxCover(outputContainer, *itr, orient, node->rect); //get rectangles down path Interval nodeIvl = (*itr)->rect.get(orient); if(contains(nodeIvl, rectIvl, true)) writeOut = false; } if(writeOut) { //std::cout << "WRITE OUT 2: " << node->rect << std::endl; outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(node->rect)); } } struct stack_element { inline stack_element() : node(), rect(), itr() {} inline stack_element(Node* n, const Rectangle& r, typename Node::iterator i) : node(n), rect(r), itr(i) {} Node* node; Rectangle rect; typename Node::iterator itr; }; template <class cT> static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient, Rectangle rect) { //std::cout << "New Root\n"; std::vector<stack_element> stack; typename Node::iterator itr = node->begin(); do { //std::cout << "LOOP\n"; //std::cout << node->rect << std::endl; Interval rectIvl = rect.get(orient); Interval nodeIvl = node->rect.get(orient); bool iresult = intersect(rectIvl, nodeIvl, false); bool tresult = !node->tracedPath(rectIvl); //std::cout << (itr != node->end()) << " " << iresult << " " << tresult << std::endl; Rectangle nextRect1 = Rectangle(rectIvl, rectIvl); Unit low = rect.get(orient.get_perpendicular()).low(); Unit high = node->rect.get(orient.get_perpendicular()).high(); nextRect1.set(orient.get_perpendicular(), Interval(low, high)); if(iresult && tresult) { node->addPath(rectIvl); bool writeOut = true; //check further visibility beyond this node for(typename Node::iterator itr2 = node->begin(); itr2 != node->end(); ++itr2) { Interval nodeIvl3 = (*itr2)->rect.get(orient); //if a child of this node can contain the interval then we can extend through if(contains(nodeIvl3, rectIvl, true)) writeOut = false; //std::cout << "child " << (*itr2)->rect << std::endl; } Rectangle nextRect2 = Rectangle(rectIvl, rectIvl); Unit low2 = rect.get(orient.get_perpendicular()).low(); Unit high2 = node->rect.get(orient.get_perpendicular()).high(); nextRect2.set(orient.get_perpendicular(), Interval(low2, high2)); if(writeOut) { //std::cout << "write out " << nextRect << std::endl; outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(nextRect2)); } else { //std::cout << "suppress " << nextRect << std::endl; } } if(itr != node->end() && iresult && tresult) { //std::cout << "recurse into child\n"; stack.push_back(stack_element(node, rect, itr)); rect = nextRect1; node = *itr; itr = node->begin(); } else { if(!stack.empty()) { //std::cout << "recurse out of child\n"; node = stack.back().node; rect = stack.back().rect; itr = stack.back().itr; stack.pop_back(); } else { //std::cout << "empty stack\n"; //if there were no children of the root node // Rectangle nextRect = Rectangle(rectIvl, rectIvl); // Unit low = rect.get(orient.get_perpendicular()).low(); // Unit high = node->rect.get(orient.get_perpendicular()).high(); // nextRect.set(orient.get_perpendicular(), Interval(low, high)); // outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(nextRect)); } //std::cout << "increment " << (itr != node->end()) << std::endl; if(itr != node->end()) { ++itr; if(itr != node->end()) { //std::cout << "recurse into next child.\n"; stack.push_back(stack_element(node, rect, itr)); Interval rectIvl2 = rect.get(orient); Interval nodeIvl2 = node->rect.get(orient); /*bool iresult =*/ intersect(rectIvl2, nodeIvl2, false); Rectangle nextRect2 = Rectangle(rectIvl2, rectIvl2); Unit low2 = rect.get(orient.get_perpendicular()).low(); Unit high2 = node->rect.get(orient.get_perpendicular()).high(); nextRect2.set(orient.get_perpendicular(), Interval(low2, high2)); rect = nextRect2; //std::cout << "rect for next child" << rect << std::endl; node = *itr; itr = node->begin(); } } } } while(!stack.empty() || itr != node->end()); } /* Function recursive version of getMaxCover Because the code is so much simpler than the loop algorithm I retain it for clarity template <class cT> static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient, const Rectangle& rect) { Interval rectIvl = rect.get(orient); Interval nodeIvl = node->rect.get(orient); if(!intersect(rectIvl, nodeIvl, false)) { return; } if(node->tracedPath(rectIvl)) { return; } node->addPath(rectIvl); Rectangle nextRect(rectIvl, rectIvl); Unit low = rect.get(orient.get_perpendicular()).low(); Unit high = node->rect.get(orient.get_perpendicular()).high(); nextRect.set(orient.get_perpendicular(), Interval(low, high)); bool writeOut = true; rectIvl = nextRect.get(orient); for(typename Node::iterator itr = node->begin(); itr != node->end(); ++itr) { nodeIvl = (*itr)->rect.get(orient); if(contains(nodeIvl, rectIvl, true)) writeOut = false; } if(writeOut) { outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(nextRect)); } for(typename Node::iterator itr = node->begin(); itr != node->end(); ++itr) { getMaxCover(outputContainer, *itr, orient, nextRect); } } */ //iterator range is assummed to be in topological order meaning all node's trailing //edges are in sorted order template <class iT> static inline void computeDag(iT beginNode, iT endNode, orientation_2d orient, std::size_t size) { std::vector<EdgeAssociation> leadingEdges; leadingEdges.reserve(size); for(iT iter = beginNode; iter != endNode; ++iter) { Node* nodep = &(*iter); Unit leading = nodep->rect.get(orient.get_perpendicular()).low(); Interval rectIvl = nodep->rect.get(orient); leadingEdges.push_back(EdgeAssociation(std::pair<Unit, Interval>(leading, rectIvl), nodep)); } polygon_sort(leadingEdges.begin(), leadingEdges.end(), lessEdgeAssociation()); typename std::vector<EdgeAssociation>::iterator leadingBegin = leadingEdges.begin(); iT trailingBegin = beginNode; while(leadingBegin != leadingEdges.end()) { EdgeAssociation& leadingSegment = (*leadingBegin); Unit trailing = (*trailingBegin).rect.get(orient.get_perpendicular()).high(); Interval ivl = (*trailingBegin).rect.get(orient); std::pair<Unit, Interval> trailingSegment(trailing, ivl); if(leadingSegment.first.first < trailingSegment.first) { ++leadingBegin; continue; } if(leadingSegment.first.first > trailingSegment.first) { ++trailingBegin; continue; } if(leadingSegment.first.second.high() <= trailingSegment.second.low()) { ++leadingBegin; continue; } if(trailingSegment.second.high() <= leadingSegment.first.second.low()) { ++trailingBegin; continue; } //leading segment intersects trailing segment (*trailingBegin).add((*leadingBegin).second); if(leadingSegment.first.second.high() > trailingSegment.second.high()) { ++trailingBegin; continue; } if(trailingSegment.second.high() > leadingSegment.first.second.high()) { ++leadingBegin; continue; } ++leadingBegin; ++trailingBegin; } } template <class cT> static inline void getMaxCover(cT& outputContainer, const std::vector<Rectangle>& rects, orientation_2d orient) { if(rects.empty()) return; std::vector<Node> nodes; { if(rects.size() == 1) { outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(rects[0])); return; } nodes.reserve(rects.size()); for(std::size_t i = 0; i < rects.size(); ++i) { nodes.push_back(Node(rects[i])); } } computeDag(nodes.begin(), nodes.end(), orient, nodes.size()); for(std::size_t i = 0; i < nodes.size(); ++i) { getMaxCover(outputContainer, &(nodes[i]), orient); } } }; } } #endif detail/property_merge_45.hpp 0000644 00000014307 15125572616 0012111 0 ustar 00 /* 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_PROPERTY_MERGE_45_HPP #define BOOST_POLYGON_PROPERTY_MERGE_45_HPP namespace boost { namespace polygon{ template <typename Unit, typename property_type> struct polygon_45_property_merge { typedef point_data<Unit> Point; typedef typename coordinate_traits<Unit>::manhattan_area_type LongUnit; template <typename property_map> static inline void merge_property_maps(property_map& mp, const property_map& mp2, bool subtract = false) { polygon_45_touch<Unit>::merge_property_maps(mp, mp2, subtract); } class CountMerge { public: inline CountMerge() : counts() {} //inline CountMerge(int count) { counts[0] = counts[1] = count; } //inline CountMerge(int count1, int count2) { counts[0] = count1; counts[1] = count2; } inline CountMerge(const CountMerge& count) : counts(count.counts) {} inline bool operator==(const CountMerge& count) const { return counts == count.counts; } inline bool operator!=(const CountMerge& count) const { return !((*this) == count); } //inline CountMerge& operator=(int count) { counts[0] = counts[1] = count; return *this; } inline CountMerge& operator=(const CountMerge& count) { counts = count.counts; return *this; } inline int& operator[](property_type index) { std::vector<std::pair<int, int> >::iterator itr = lower_bound(counts.begin(), counts.end(), std::make_pair(index, int(0))); if(itr != counts.end() && itr->first == index) { return itr->second; } itr = counts.insert(itr, std::make_pair(index, int(0))); return itr->second; } // inline int operator[](int index) const { // std::vector<std::pair<int, int> >::const_iterator itr = counts.begin(); // for( ; itr != counts.end() && itr->first <= index; ++itr) { // if(itr->first == index) { // return itr->second; // } // } // return 0; // } inline CountMerge& operator+=(const CountMerge& count){ merge_property_maps(counts, count.counts, false); return *this; } inline CountMerge& operator-=(const CountMerge& count){ merge_property_maps(counts, count.counts, true); return *this; } inline CountMerge operator+(const CountMerge& count) const { return CountMerge(*this)+=count; } inline CountMerge operator-(const CountMerge& count) const { return CountMerge(*this)-=count; } inline CountMerge invert() const { CountMerge retval; retval -= *this; return retval; } std::vector<std::pair<property_type, int> > counts; }; //output is a std::map<std::set<property_type>, polygon_45_set_data<Unit> > struct merge_45_output_functor { template <typename cT> void operator()(cT& output, const CountMerge& count1, const CountMerge& count2, const Point& pt, int rise, direction_1d end) { typedef typename cT::key_type keytype; keytype left; keytype right; int edgeType = end == LOW ? -1 : 1; for(typename std::vector<std::pair<property_type, int> >::const_iterator itr = count1.counts.begin(); itr != count1.counts.end(); ++itr) { left.insert(left.end(), (*itr).first); } for(typename std::vector<std::pair<property_type, int> >::const_iterator itr = count2.counts.begin(); itr != count2.counts.end(); ++itr) { right.insert(right.end(), (*itr).first); } if(left == right) return; if(!left.empty()) { //std::cout << pt.x() << " " << pt.y() << " " << rise << " " << edgeType << std::endl; output[left].insert_clean(typename boolean_op_45<Unit>::Vertex45(pt, rise, -edgeType)); } if(!right.empty()) { //std::cout << pt.x() << " " << pt.y() << " " << rise << " " << -edgeType << std::endl; output[right].insert_clean(typename boolean_op_45<Unit>::Vertex45(pt, rise, edgeType)); } } }; typedef typename std::pair<Point, typename boolean_op_45<Unit>::template Scan45CountT<CountMerge> > Vertex45Compact; typedef std::vector<Vertex45Compact> MergeSetData; struct lessVertex45Compact { bool operator()(const Vertex45Compact& l, const Vertex45Compact& r) { return l.first < r.first; } }; template <typename output_type> static void performMerge(output_type& result, MergeSetData& tsd) { polygon_sort(tsd.begin(), tsd.end(), lessVertex45Compact()); typedef std::vector<std::pair<Point, typename boolean_op_45<Unit>::template Scan45CountT<CountMerge> > > TSD; TSD tsd_; tsd_.reserve(tsd.size()); for(typename MergeSetData::iterator itr = tsd.begin(); itr != tsd.end(); ) { typename MergeSetData::iterator itr2 = itr; ++itr2; for(; itr2 != tsd.end() && itr2->first == itr->first; ++itr2) { (itr->second) += (itr2->second); //accumulate } tsd_.push_back(std::make_pair(itr->first, itr->second)); itr = itr2; } typename boolean_op_45<Unit>::template Scan45<CountMerge, merge_45_output_functor> scanline; for(typename TSD::iterator itr = tsd_.begin(); itr != tsd_.end(); ) { typename TSD::iterator itr2 = itr; ++itr2; while(itr2 != tsd_.end() && itr2->first.x() == itr->first.x()) { ++itr2; } scanline.scan(result, itr, itr2); itr = itr2; } } template <typename iT> static void populateMergeSetData(MergeSetData& tsd, iT begin, iT end, property_type property) { for( ; begin != end; ++begin) { Vertex45Compact vertex; vertex.first = typename Vertex45Compact::first_type(begin->pt.x() * 2, begin->pt.y() * 2); tsd.push_back(vertex); for(unsigned int i = 0; i < 4; ++i) { if(begin->count[i]) { tsd.back().second[i][property] += begin->count[i]; } } } } }; } } #endif detail/polygon_formation.hpp 0000644 00000253620 15125572616 0012306 0 ustar 00 /* 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). */ #include<iostream> #include<cassert> #ifndef BOOST_POLYGON_POLYGON_FORMATION_HPP #define BOOST_POLYGON_POLYGON_FORMATION_HPP namespace boost { namespace polygon{ namespace polygon_formation { /* * End has two states, HEAD and TAIL as is represented by a bool */ typedef bool End; /* * HEAD End is represented as false because it is the lesser state */ const End HEAD = false; /* * TAIL End is represented by true because TAIL comes after head and 1 after 0 */ const End TAIL = true; /* * 2D turning direction, left and right sides (is a boolean value since it has two states.) */ typedef bool Side; /* * LEFT Side is 0 because we inuitively think left to right; left < right */ const Side LEFT = false; /* * RIGHT Side is 1 so that right > left */ const Side RIGHT = true; /* * The PolyLine class is data storage and services for building and representing partial polygons. * As the polyline is added to it extends its storage to accomodate the data. * PolyLines can be joined head-to-head/head-to-tail when it is determined that two polylines are * part of the same polygon. * PolyLines keep state information about what orientation their incomplete head and tail geometry have, * which side of the polyline is solid and whether the polyline is joined head-to-head and tail-to-head. * PolyLines have nothing whatsoever to do with holes. * It may be valuable to collect a histogram of PolyLine lengths used by an algorithm on its typical data * sets and tune the allocation of the initial vector of coordinate data to be greater than or equal to * the mean, median, mode, or mean plus some number of standard deviation, or just generally large enough * to prevent too much unnecesary reallocations, but not too big that it wastes a lot of memory and degrades cache * performance. */ template <typename Unit> class PolyLine { private: //data /* * ptdata_ a vector of coordiantes * if VERTICAL_HEAD, first coordiante is an X * else first coordinate is a Y */ std::vector<Unit> ptdata_; /* * head and tail points to other polylines before and after this in a chain */ PolyLine* headp_; PolyLine* tailp_; /* * state bitmask * bit zero is orientation, 0 H, 1 V * bit 1 is head connectivity, 0 for head, 1 for tail * bit 2 is tail connectivity, 0 for head, 1 for tail * bit 3 is solid to left of PolyLine when 1, right when 0 */ int state_; public: /* * default constructor (for preallocation) */ PolyLine(); /* * constructor that takes the orientation, coordiante and side to which there is solid */ PolyLine(orientation_2d orient, Unit coord, Side side); //copy constructor PolyLine(const PolyLine& pline); //destructor ~PolyLine(); //assignment operator PolyLine& operator=(const PolyLine& that); //equivalence operator bool operator==(const PolyLine& b) const; /* * valid PolyLine (only default constructed polylines are invalid.) */ bool isValid() const; /* * Orientation of Head */ orientation_2d headOrient() const; /* * returns true if first coordinate is an X value (first segment is vertical) */ bool verticalHead() const; /* * returns the orientation_2d fo the tail */ orientation_2d tailOrient() const; /* * returns true if last coordinate is an X value (last segment is vertical) */ bool verticalTail() const; /* * retrun true if PolyLine has odd number of coordiantes */ bool oddLength() const; /* * retrun the End of the other polyline that the specified end of this polyline is connected to */ End endConnectivity(End end) const; /* * retrun true if the head of this polyline is connect to the tail of a polyline */ bool headToTail() const; /* * retrun true if the head of this polyline is connect to the head of a polyline */ bool headToHead() const; /* * retrun true if the tail of this polyline is connect to the tail of a polyline */ bool tailToTail() const; /* * retrun true if the tail of this polyline is connect to the head of a polyline */ bool tailToHead() const; /* * retrun the side on which there is solid for this polyline */ Side solidSide() const; /* * retrun true if there is solid to the right of this polyline */ bool solidToRight() const; /* * returns true if the polyline tail is not connected */ bool active() const; /* * adds a coordinate value to the end of the polyline changing the tail orientation */ PolyLine& pushCoordinate(Unit coord); /* * removes a coordinate value at the end of the polyline changing the tail orientation */ PolyLine& popCoordinate(); /* * extends the tail of the polyline to include the point, changing orientation if needed */ PolyLine& pushPoint(const point_data<Unit>& point); /* * changes the last coordinate of the tail of the polyline by the amount of the delta */ PolyLine& extendTail(Unit delta); /* * join thisEnd of this polyline to that polyline's end */ PolyLine& joinTo(End thisEnd, PolyLine& that, End end); /* * join an end of this polyline to the tail of that polyline */ PolyLine& joinToTail(PolyLine& that, End end); /* * join an end of this polyline to the head of that polyline */ PolyLine& joinToHead(PolyLine& that, End end); /* * join the head of this polyline to the head of that polyline */ //join this to that in the given way PolyLine& joinHeadToHead(PolyLine& that); /* * join the head of this polyline to the tail of that polyline */ PolyLine& joinHeadToTail(PolyLine& that); /* * join the tail of this polyline to the head of that polyline */ PolyLine& joinTailToHead(PolyLine& that); /* * join the tail of this polyline to the tail of that polyline */ PolyLine& joinTailToTail(PolyLine& that); /* * dissconnect the tail at the end of the polygon */ PolyLine& disconnectTails(); /* * get the coordinate at one end of this polyline, by default the tail end */ Unit getEndCoord(End end = TAIL) const; /* * get the point on the polyline at the given index (polylines have the same number of coordinates as points */ point_data<Unit> getPoint(unsigned int index) const; /* * get the point on one end of the polyline, by default the tail */ point_data<Unit> getEndPoint(End end = TAIL) const; /* * get the orientation of a segment by index */ orientation_2d segmentOrient(unsigned int index = 0) const; /* * get a coordinate by index using the square bracket operator */ Unit operator[] (unsigned int index) const; /* * get the number of segments/points/coordinates in the polyline */ unsigned int numSegments() const; /* * get the pointer to the next polyline at one end of this */ PolyLine* next(End end) const; /* * write out coordinates of this and all attached polylines to a single vector */ PolyLine* writeOut(std::vector<Unit>& outVec, End startEnd = TAIL) const; private: //methods PolyLine& joinTo_(End thisEnd, PolyLine& that, End end); }; //forward declaration template<bool orientT, typename Unit> class PolyLinePolygonData; //forward declaration template<bool orientT, typename Unit> class PolyLinePolygonWithHolesData; /* * ActiveTail represents an edge of an incomplete polygon. * * An ActiveTail object is the active tail end of a polyline object, which may (should) be the attached to * a chain of polyline objects through a pointer. The ActiveTail class provides an abstraction between * and algorithm that builds polygons and the PolyLine data representation of incomplete polygons that are * being built. It does this by providing an iterface to access the information about the last edge at the * tail of the PolyLine it is associated with. To a polygon constructing algorithm, an ActiveTail is a floating * edge of an incomplete polygon and has an orientation and coordinate value, as well as knowing which side of * that edge is supposed to be solid or space. Any incomplete polygon will have two active tails. Active tails * may be joined together to merge two incomplete polygons into a larger incomplete polygon. If two active tails * that are to be merged are the oppositve ends of the same incomplete polygon that indicates that the polygon * has been closed and is complete. The active tail keeps a pointer to the other active tail of its incomplete * polygon so that it is easy to check this condition. These pointers are updated when active tails are joined. * The active tail also keeps a list of pointers to active tail objects that serve as handles to closed holes. In * this way a hole can be associated to another incomplete polygon, which will eventually be its enclosing shell, * or reassociate the hole to another incomplete polygon in the case that it become a hole itself. Alternately, * the active tail may add a filiment to stitch a hole into a shell and "fracture" the hole out of the interior * of a polygon. The active tail maintains a static output buffer to temporarily write polygon data to when * it outputs a figure so that outputting a polygon does not require the allocation of a temporary buffer. This * static buffer should be destroyed whenever the program determines that it won't need it anymore and would prefer to * release the memory it has allocated back to the system. */ template <typename Unit> class ActiveTail { private: //data PolyLine<Unit>* tailp_; ActiveTail *otherTailp_; std::list<ActiveTail*> holesList_; //Sum of all the polylines which constitute the active tail (including holes)// size_t polyLineSize_; public: inline size_t getPolyLineSize(){ return polyLineSize_; } inline void setPolyLineSize(int delta){ polyLineSize_ = delta; } inline void addPolyLineSize(int delta){ polyLineSize_ += delta; } /* * iterator over coordinates of the figure */ class iterator { private: const PolyLine<Unit>* pLine_; const PolyLine<Unit>* pLineEnd_; unsigned int index_; unsigned int indexEnd_; End startEnd_; public: inline iterator() : pLine_(), pLineEnd_(), index_(), indexEnd_(), startEnd_() {} inline iterator(const ActiveTail* at, bool isHole, orientation_2d orient) : pLine_(), pLineEnd_(), index_(), indexEnd_(), startEnd_() { //if it is a hole and orientation is vertical or it is not a hole and orientation is horizontal //we want to use this active tail, otherwise we want to use the other active tail startEnd_ = TAIL; if(!isHole ^ (orient == HORIZONTAL)) { //switch winding direction at = at->getOtherActiveTail(); } //now we have the right winding direction //if it is horizontal we need to skip the first element pLine_ = at->getTail(); if(at->getTail()->numSegments() > 0) index_ = at->getTail()->numSegments() - 1; if((at->getOrient() == HORIZONTAL) ^ (orient == HORIZONTAL)) { pLineEnd_ = at->getTail(); indexEnd_ = pLineEnd_->numSegments() - 1; if(index_ == 0) { pLine_ = at->getTail()->next(HEAD); if(at->getTail()->endConnectivity(HEAD) == TAIL) { index_ = pLine_->numSegments() -1; } else { startEnd_ = HEAD; index_ = 0; } } else { --index_; } } else { pLineEnd_ = at->getOtherActiveTail()->getTail(); if(pLineEnd_->numSegments() > 0) indexEnd_ = pLineEnd_->numSegments() - 1; } at->getTail()->joinTailToTail(*(at->getOtherActiveTail()->getTail())); } inline size_t size(void){ size_t count = 0; End dir = startEnd_; PolyLine<Unit> const * currLine = pLine_; size_t ops = 0; while(currLine != pLineEnd_){ ops++; count += currLine->numSegments(); currLine = currLine->next(dir == HEAD ? TAIL : HEAD); dir = currLine->endConnectivity(dir == HEAD ? TAIL : HEAD); } count += pLineEnd_->numSegments(); return count; //no. of vertices } //use bitwise copy and assign provided by the compiler inline iterator& operator++() { if(pLine_ == pLineEnd_ && index_ == indexEnd_) { pLine_ = 0; index_ = 0; return *this; } if(startEnd_ == HEAD) { ++index_; if(index_ == pLine_->numSegments()) { End end = pLine_->endConnectivity(TAIL); pLine_ = pLine_->next(TAIL); if(end == TAIL) { startEnd_ = TAIL; index_ = pLine_->numSegments() -1; } else { index_ = 0; } } } else { if(index_ == 0) { End end = pLine_->endConnectivity(HEAD); pLine_ = pLine_->next(HEAD); if(end == TAIL) { index_ = pLine_->numSegments() -1; } else { startEnd_ = HEAD; index_ = 0; } } else { --index_; } } return *this; } inline const iterator operator++(int) { iterator tmp(*this); ++(*this); return tmp; } inline bool operator==(const iterator& that) const { return pLine_ == that.pLine_ && index_ == that.index_; } inline bool operator!=(const iterator& that) const { return pLine_ != that.pLine_ || index_ != that.index_; } inline Unit operator*() { return (*pLine_)[index_]; } }; /* * iterator over holes contained within the figure */ typedef typename std::list<ActiveTail*>::const_iterator iteratorHoles; //default constructor ActiveTail(); //constructor ActiveTail(orientation_2d orient, Unit coord, Side solidToRight, ActiveTail* otherTailp); //constructor ActiveTail(PolyLine<Unit>* active, ActiveTail* otherTailp); //copy constructor ActiveTail(const ActiveTail& that); //destructor ~ActiveTail(); //assignment operator ActiveTail& operator=(const ActiveTail& that); //equivalence operator bool operator==(const ActiveTail& b) const; /* * comparison operators, ActiveTail objects are sortable by geometry */ bool operator<(const ActiveTail& b) const; bool operator<=(const ActiveTail& b) const; bool operator>(const ActiveTail& b) const; bool operator>=(const ActiveTail& b) const; /* * get the pointer to the polyline that this is an active tail of */ PolyLine<Unit>* getTail() const; /* * get the pointer to the polyline at the other end of the chain */ PolyLine<Unit>* getOtherTail() const; /* * get the pointer to the activetail at the other end of the chain */ ActiveTail* getOtherActiveTail() const; /* * test if another active tail is the other end of the chain */ bool isOtherTail(const ActiveTail& b); /* * update this end of chain pointer to new polyline */ ActiveTail& updateTail(PolyLine<Unit>* newTail); /* * associate a hole to this active tail by the specified policy */ ActiveTail* addHole(ActiveTail* hole, bool fractureHoles); /* * get the list of holes */ const std::list<ActiveTail*>& getHoles() const; /* * copy holes from that to this */ void copyHoles(ActiveTail& that); /* * find out if solid to right */ bool solidToRight() const; /* * get coordinate (getCoord and getCoordinate are aliases for eachother) */ Unit getCoord() const; Unit getCoordinate() const; /* * get the tail orientation */ orientation_2d getOrient() const; /* * add a coordinate to the polygon at this active tail end, properly handle degenerate edges by removing redundant coordinate */ void pushCoordinate(Unit coord); /* * write the figure that this active tail points to out to the temp buffer */ void writeOutFigure(std::vector<Unit>& outVec, bool isHole = false) const; /* * write the figure that this active tail points to out through iterators */ void writeOutFigureItrs(iterator& beginOut, iterator& endOut, bool isHole = false, orientation_2d orient = VERTICAL) const; iterator begin(bool isHole, orientation_2d orient) const; iterator end() const; /* * write the holes that this active tail points to out through iterators */ void writeOutFigureHoleItrs(iteratorHoles& beginOut, iteratorHoles& endOut) const; iteratorHoles beginHoles() const; iteratorHoles endHoles() const; /* * joins the two chains that the two active tail tails are ends of * checks for closure of figure and writes out polygons appropriately * returns a handle to a hole if one is closed */ static ActiveTail* joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, std::vector<Unit>& outBufferTmp); template <typename PolygonT> static ActiveTail* joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, typename std::vector<PolygonT>& outBufferTmp); /* * deallocate temp buffer */ static void destroyOutBuffer(); /* * deallocate all polygon data this active tail points to (deep delete, call only from one of a pair of active tails) */ void destroyContents(); }; /* allocate a polyline object */ template <typename Unit> PolyLine<Unit>* createPolyLine(orientation_2d orient, Unit coord, Side side); /* deallocate a polyline object */ template <typename Unit> void destroyPolyLine(PolyLine<Unit>* pLine); /* allocate an activetail object */ template <typename Unit> ActiveTail<Unit>* createActiveTail(); /* deallocate an activetail object */ template <typename Unit> void destroyActiveTail(ActiveTail<Unit>* aTail); template<bool orientT, typename Unit> class PolyLineHoleData { private: ActiveTail<Unit>* p_; public: typedef Unit coordinate_type; typedef typename ActiveTail<Unit>::iterator compact_iterator_type; typedef iterator_compact_to_points<compact_iterator_type, point_data<coordinate_type> > iterator_type; inline PolyLineHoleData() : p_(0) {} inline PolyLineHoleData(ActiveTail<Unit>* p) : p_(p) {} //use default copy and assign inline compact_iterator_type begin_compact() const { return p_->begin(true, (orientT ? VERTICAL : HORIZONTAL)); } inline compact_iterator_type end_compact() const { return p_->end(); } inline iterator_type begin() const { return iterator_type(begin_compact(), end_compact()); } inline iterator_type end() const { return iterator_type(end_compact(), end_compact()); } inline std::size_t size() const { return p_->getPolyLineSize(); } inline ActiveTail<Unit>* yield() { return p_; } }; template<bool orientT, typename Unit> class PolyLinePolygonWithHolesData { private: ActiveTail<Unit>* p_; public: typedef Unit coordinate_type; typedef typename ActiveTail<Unit>::iterator compact_iterator_type; typedef iterator_compact_to_points<compact_iterator_type, point_data<coordinate_type> > iterator_type; typedef PolyLineHoleData<orientT, Unit> hole_type; typedef typename coordinate_traits<Unit>::area_type area_type; class iteratorHoles { private: typename ActiveTail<Unit>::iteratorHoles itr_; public: inline iteratorHoles() : itr_() {} inline iteratorHoles(typename ActiveTail<Unit>::iteratorHoles itr) : itr_(itr) {} //use bitwise copy and assign provided by the compiler inline iteratorHoles& operator++() { ++itr_; return *this; } inline const iteratorHoles operator++(int) { iteratorHoles tmp(*this); ++(*this); return tmp; } inline bool operator==(const iteratorHoles& that) const { return itr_ == that.itr_; } inline bool operator!=(const iteratorHoles& that) const { return itr_ != that.itr_; } inline PolyLineHoleData<orientT, Unit> operator*() { return PolyLineHoleData<orientT, Unit>(*itr_);} }; typedef iteratorHoles iterator_holes_type; inline PolyLinePolygonWithHolesData() : p_(0) {} inline PolyLinePolygonWithHolesData(ActiveTail<Unit>* p) : p_(p) {} //use default copy and assign inline compact_iterator_type begin_compact() const { return p_->begin(false, (orientT ? VERTICAL : HORIZONTAL)); } inline compact_iterator_type end_compact() const { return p_->end(); } inline iterator_type begin() const { return iterator_type(begin_compact(), end_compact()); } inline iterator_type end() const { return iterator_type(end_compact(), end_compact()); } inline iteratorHoles begin_holes() const { return iteratorHoles(p_->beginHoles()); } inline iteratorHoles end_holes() const { return iteratorHoles(p_->endHoles()); } inline ActiveTail<Unit>* yield() { return p_; } //stub out these four required functions that will not be used but are needed for the interface inline std::size_t size_holes() const { return 0; } inline std::size_t size() const { return 0; } }; template <bool orientT, typename Unit, typename polygon_concept_type> struct PolyLineType { }; template <bool orientT, typename Unit> struct PolyLineType<orientT, Unit, polygon_90_with_holes_concept> { typedef PolyLinePolygonWithHolesData<orientT, Unit> type; }; template <bool orientT, typename Unit> struct PolyLineType<orientT, Unit, polygon_45_with_holes_concept> { typedef PolyLinePolygonWithHolesData<orientT, Unit> type; }; template <bool orientT, typename Unit> struct PolyLineType<orientT, Unit, polygon_with_holes_concept> { typedef PolyLinePolygonWithHolesData<orientT, Unit> type; }; template <bool orientT, typename Unit> struct PolyLineType<orientT, Unit, polygon_90_concept> { typedef PolyLineHoleData<orientT, Unit> type; }; template <bool orientT, typename Unit> struct PolyLineType<orientT, Unit, polygon_45_concept> { typedef PolyLineHoleData<orientT, Unit> type; }; template <bool orientT, typename Unit> struct PolyLineType<orientT, Unit, polygon_concept> { typedef PolyLineHoleData<orientT, Unit> type; }; template <bool orientT, typename Unit, typename polygon_concept_type> class ScanLineToPolygonItrs { private: std::map<Unit, ActiveTail<Unit>*> tailMap_; typedef typename PolyLineType<orientT, Unit, polygon_concept_type>::type PolyLinePolygonData; std::vector<PolyLinePolygonData> outputPolygons_; bool fractureHoles_; public: typedef typename std::vector<PolyLinePolygonData>::iterator iterator; inline ScanLineToPolygonItrs() : tailMap_(), outputPolygons_(), fractureHoles_(false) {} /* construct a scanline with the proper offsets, protocol and options */ inline ScanLineToPolygonItrs(bool fractureHoles) : tailMap_(), outputPolygons_(), fractureHoles_(fractureHoles) {} ~ScanLineToPolygonItrs() { clearOutput_(); } /* process all vertical edges, left and right, at a unique x coordinate, edges must be sorted low to high */ void processEdges(iterator& beginOutput, iterator& endOutput, Unit currentX, std::vector<interval_data<Unit> >& leftEdges, std::vector<interval_data<Unit> >& rightEdges, size_t vertexThreshold=(std::numeric_limits<size_t>::max)() ); /********************************************************************** *methods implementing new polygon formation code * **********************************************************************/ void updatePartialSimplePolygonsWithRightEdges(Unit currentX, const std::vector<interval_data<Unit> >& leftEdges, size_t threshold); void updatePartialSimplePolygonsWithLeftEdges(Unit currentX, const std::vector<interval_data<Unit> >& leftEdges, size_t threshold); void closePartialSimplePolygon(Unit, ActiveTail<Unit>*, ActiveTail<Unit>*); void maintainPartialSimplePolygonInvariant(iterator& ,iterator& ,Unit, const std::vector<interval_data<Unit> >&, const std::vector<interval_data<Unit> >&, size_t vertexThreshold=(std::numeric_limits<size_t>::max)()); void insertNewLeftEdgeIntoTailMap(Unit, Unit, Unit, typename std::map<Unit, ActiveTail<Unit>*>::iterator &); /**********************************************************************/ inline size_t getTailMapSize(){ typename std::map<Unit, ActiveTail<Unit>* >::const_iterator itr; size_t tsize = 0; for(itr=tailMap_.begin(); itr!=tailMap_.end(); ++itr){ tsize += (itr->second)->getPolyLineSize(); } return tsize; } /*print the active tails in this map:*/ inline void print(){ typename std::map<Unit, ActiveTail<Unit>* >::const_iterator itr; printf("=========TailMap[%lu]=========\n", tailMap_.size()); for(itr=tailMap_.begin(); itr!=tailMap_.end(); ++itr){ std::cout<< "[" << itr->first << "] : " << std::endl; //print active tail// ActiveTail<Unit> const *t = (itr->second); PolyLine<Unit> const *pBegin = t->getTail(); PolyLine<Unit> const *pEnd = t->getOtherActiveTail()->getTail(); std::string sorient = pBegin->solidToRight() ? "RIGHT" : "LEFT"; std::cout<< " ActiveTail.tailp_ (solid= " << sorient ; End dir = TAIL; while(pBegin!=pEnd){ std::cout << pBegin << "={ "; for(size_t i=0; i<pBegin->numSegments(); i++){ point_data<Unit> u = pBegin->getPoint(i); std::cout << "(" << u.x() << "," << u.y() << ") "; } std::cout << "} "; pBegin = pBegin->next(dir == HEAD ? TAIL : HEAD); dir = pBegin->endConnectivity(dir == HEAD ? TAIL : HEAD); } if(pEnd){ std::cout << pEnd << "={ "; for(size_t i=0; i<pEnd->numSegments(); i++){ point_data<Unit> u = pEnd->getPoint(i); std::cout << "(" << u.x() << "," << u.y() << ") "; } std::cout << "} "; } std::cout << " end= " << pEnd << std::endl; } } private: void clearOutput_(); }; /* * ScanLine does all the work of stitching together polygons from incoming vertical edges */ // template <typename Unit, typename polygon_concept_type> // class ScanLineToPolygons { // private: // ScanLineToPolygonItrs<true, Unit> scanline_; // public: // inline ScanLineToPolygons() : scanline_() {} // /* construct a scanline with the proper offsets, protocol and options */ // inline ScanLineToPolygons(bool fractureHoles) : scanline_(fractureHoles) {} // /* process all vertical edges, left and right, at a unique x coordinate, edges must be sorted low to high */ // inline void processEdges(std::vector<Unit>& outBufferTmp, Unit currentX, std::vector<interval_data<Unit> >& leftEdges, // std::vector<interval_data<Unit> >& rightEdges) { // typename ScanLineToPolygonItrs<true, Unit>::iterator itr, endItr; // scanline_.processEdges(itr, endItr, currentX, leftEdges, rightEdges); // //copy data into outBufferTmp // while(itr != endItr) { // typename PolyLinePolygonData<true, Unit>::iterator pditr; // outBufferTmp.push_back(0); // unsigned int sizeIndex = outBufferTmp.size() - 1; // int count = 0; // for(pditr = (*itr).begin(); pditr != (*itr).end(); ++pditr) { // outBufferTmp.push_back(*pditr); // ++count; // } // outBufferTmp[sizeIndex] = count; // typename PolyLinePolygonData<true, Unit>::iteratorHoles pdHoleItr; // for(pdHoleItr = (*itr).beginHoles(); pdHoleItr != (*itr).endHoles(); ++pdHoleItr) { // outBufferTmp.push_back(0); // unsigned int sizeIndex2 = outBufferTmp.size() - 1; // int count2 = 0; // for(pditr = (*pdHoleItr).begin(); pditr != (*pdHoleItr).end(); ++pditr) { // outBufferTmp.push_back(*pditr); // ++count2; // } // outBufferTmp[sizeIndex2] = -count; // } // ++itr; // } // } // }; const int VERTICAL_HEAD = 1, HEAD_TO_TAIL = 2, TAIL_TO_TAIL = 4, SOLID_TO_RIGHT = 8; //EVERY FUNCTION in this DEF file should be explicitly defined as inline //microsoft compiler improperly warns whenever you cast an integer to bool //call this function on an integer to convert it to bool without a warning template <class T> inline bool to_bool(const T& val) { return val != 0; } //default constructor (for preallocation) template <typename Unit> inline PolyLine<Unit>::PolyLine() : ptdata_() ,headp_(0), tailp_(0), state_(-1) {} //constructor template <typename Unit> inline PolyLine<Unit>::PolyLine(orientation_2d orient, Unit coord, Side side) : ptdata_(1, coord), headp_(0), tailp_(0), state_(orient.to_int() + (side << 3)){} //copy constructor template <typename Unit> inline PolyLine<Unit>::PolyLine(const PolyLine<Unit>& pline) : ptdata_(pline.ptdata_), headp_(pline.headp_), tailp_(pline.tailp_), state_(pline.state_) {} //destructor template <typename Unit> inline PolyLine<Unit>::~PolyLine() { //clear out data just in case it is read later headp_ = tailp_ = 0; state_ = 0; } template <typename Unit> inline PolyLine<Unit>& PolyLine<Unit>::operator=(const PolyLine<Unit>& that) { if(!(this == &that)) { headp_ = that.headp_; tailp_ = that.tailp_; ptdata_ = that.ptdata_; state_ = that.state_; } return *this; } template <typename Unit> inline bool PolyLine<Unit>::operator==(const PolyLine<Unit>& b) const { return this == &b || (state_ == b.state_ && headp_ == b.headp_ && tailp_ == b.tailp_); } //valid PolyLine template <typename Unit> inline bool PolyLine<Unit>::isValid() const { return state_ > -1; } //first coordinate is an X value //first segment is vertical template <typename Unit> inline bool PolyLine<Unit>::verticalHead() const { return state_ & VERTICAL_HEAD; } //retrun true is PolyLine has odd number of coordiantes template <typename Unit> inline bool PolyLine<Unit>::oddLength() const { return to_bool((ptdata_.size()-1) % 2); } //last coordiante is an X value //last segment is vertical template <typename Unit> inline bool PolyLine<Unit>::verticalTail() const { return to_bool(verticalHead() ^ oddLength()); } template <typename Unit> inline orientation_2d PolyLine<Unit>::tailOrient() const { return (verticalTail() ? VERTICAL : HORIZONTAL); } template <typename Unit> inline orientation_2d PolyLine<Unit>::headOrient() const { return (verticalHead() ? VERTICAL : HORIZONTAL); } template <typename Unit> inline End PolyLine<Unit>::endConnectivity(End end) const { //Tail should be defined as true if(end) { return tailToTail(); } return headToTail(); } template <typename Unit> inline bool PolyLine<Unit>::headToTail() const { return to_bool(state_ & HEAD_TO_TAIL); } template <typename Unit> inline bool PolyLine<Unit>::headToHead() const { return to_bool(!headToTail()); } template <typename Unit> inline bool PolyLine<Unit>::tailToHead() const { return to_bool(!tailToTail()); } template <typename Unit> inline bool PolyLine<Unit>::tailToTail() const { return to_bool(state_ & TAIL_TO_TAIL); } template <typename Unit> inline Side PolyLine<Unit>::solidSide() const { return solidToRight(); } template <typename Unit> inline bool PolyLine<Unit>::solidToRight() const { return to_bool(state_ & SOLID_TO_RIGHT) != 0; } template <typename Unit> inline bool PolyLine<Unit>::active() const { return !to_bool(tailp_); } template <typename Unit> inline PolyLine<Unit>& PolyLine<Unit>::pushCoordinate(Unit coord) { ptdata_.push_back(coord); return *this; } template <typename Unit> inline PolyLine<Unit>& PolyLine<Unit>::popCoordinate() { ptdata_.pop_back(); return *this; } template <typename Unit> inline PolyLine<Unit>& PolyLine<Unit>::pushPoint(const point_data<Unit>& point) { if(numSegments()){ point_data<Unit> endPt = getEndPoint(); //vertical is true, horizontal is false if((tailOrient().to_int() ? point.get(VERTICAL) == endPt.get(VERTICAL) : point.get(HORIZONTAL) == endPt.get(HORIZONTAL))) { //we were pushing a colinear segment return popCoordinate(); } } return pushCoordinate(tailOrient().to_int() ? point.get(VERTICAL) : point.get(HORIZONTAL)); } template <typename Unit> inline PolyLine<Unit>& PolyLine<Unit>::extendTail(Unit delta) { ptdata_.back() += delta; return *this; } //private member function that creates a link from this PolyLine to that template <typename Unit> inline PolyLine<Unit>& PolyLine<Unit>::joinTo_(End thisEnd, PolyLine<Unit>& that, End end) { if(thisEnd){ tailp_ = &that; state_ &= ~TAIL_TO_TAIL; //clear any previous state_ of bit (for safety) state_ |= (end << 2); //place bit into mask } else { headp_ = &that; state_ &= ~HEAD_TO_TAIL; //clear any previous state_ of bit (for safety) state_ |= (end << 1); //place bit into mask } return *this; } //join two PolyLines (both ways of the association) template <typename Unit> inline PolyLine<Unit>& PolyLine<Unit>::joinTo(End thisEnd, PolyLine<Unit>& that, End end) { joinTo_(thisEnd, that, end); that.joinTo_(end, *this, thisEnd); return *this; } //convenience functions for joining PolyLines template <typename Unit> inline PolyLine<Unit>& PolyLine<Unit>::joinToTail(PolyLine<Unit>& that, End end) { return joinTo(TAIL, that, end); } template <typename Unit> inline PolyLine<Unit>& PolyLine<Unit>::joinToHead(PolyLine<Unit>& that, End end) { return joinTo(HEAD, that, end); } template <typename Unit> inline PolyLine<Unit>& PolyLine<Unit>::joinHeadToHead(PolyLine<Unit>& that) { return joinToHead(that, HEAD); } template <typename Unit> inline PolyLine<Unit>& PolyLine<Unit>::joinHeadToTail(PolyLine<Unit>& that) { return joinToHead(that, TAIL); } template <typename Unit> inline PolyLine<Unit>& PolyLine<Unit>::joinTailToHead(PolyLine<Unit>& that) { return joinToTail(that, HEAD); } template <typename Unit> inline PolyLine<Unit>& PolyLine<Unit>::joinTailToTail(PolyLine<Unit>& that) { return joinToTail(that, TAIL); } template <typename Unit> inline PolyLine<Unit>& PolyLine<Unit>::disconnectTails() { next(TAIL)->state_ &= !TAIL_TO_TAIL; next(TAIL)->tailp_ = 0; state_ &= !TAIL_TO_TAIL; tailp_ = 0; return *this; } template <typename Unit> inline Unit PolyLine<Unit>::getEndCoord(End end) const { if(end) return ptdata_.back(); return ptdata_.front(); } template <typename Unit> inline orientation_2d PolyLine<Unit>::segmentOrient(unsigned int index) const { return (to_bool((unsigned int)verticalHead() ^ (index % 2)) ? VERTICAL : HORIZONTAL); } template <typename Unit> inline point_data<Unit> PolyLine<Unit>::getPoint(unsigned int index) const { //assert(isValid() && headp_->isValid()) ("PolyLine: headp_ must be valid"); point_data<Unit> pt; pt.set(HORIZONTAL, ptdata_[index]); pt.set(VERTICAL, ptdata_[index]); Unit prevCoord; if(index == 0) { prevCoord = headp_->getEndCoord(headToTail()); } else { prevCoord = ptdata_[index-1]; } pt.set(segmentOrient(index), prevCoord); return pt; } template <typename Unit> inline point_data<Unit> PolyLine<Unit>::getEndPoint(End end) const { return getPoint((end ? numSegments() - 1 : (unsigned int)0)); } template <typename Unit> inline Unit PolyLine<Unit>::operator[] (unsigned int index) const { //assert(ptdata_.size() > index) ("PolyLine: out of bounds index"); return ptdata_[index]; } template <typename Unit> inline unsigned int PolyLine<Unit>::numSegments() const { return ptdata_.size(); } template <typename Unit> inline PolyLine<Unit>* PolyLine<Unit>::next(End end) const { return (end ? tailp_ : headp_); } template <typename Unit> inline ActiveTail<Unit>::ActiveTail() : tailp_(0), otherTailp_(0), holesList_(), polyLineSize_(0) {} template <typename Unit> inline ActiveTail<Unit>::ActiveTail(orientation_2d orient, Unit coord, Side solidToRight, ActiveTail* otherTailp) : tailp_(0), otherTailp_(0), holesList_(), polyLineSize_(0) { tailp_ = createPolyLine(orient, coord, solidToRight); otherTailp_ = otherTailp; polyLineSize_ = tailp_->numSegments(); } template <typename Unit> inline ActiveTail<Unit>::ActiveTail(PolyLine<Unit>* active, ActiveTail<Unit>* otherTailp) : tailp_(active), otherTailp_(otherTailp), holesList_(), polyLineSize_(0) {} //copy constructor template <typename Unit> inline ActiveTail<Unit>::ActiveTail(const ActiveTail<Unit>& that) : tailp_(that.tailp_), otherTailp_(that.otherTailp_), holesList_(), polyLineSize_(that.polyLineSize_) {} //destructor template <typename Unit> inline ActiveTail<Unit>::~ActiveTail() { //clear them in case the memory is read later tailp_ = 0; otherTailp_ = 0; } template <typename Unit> inline ActiveTail<Unit>& ActiveTail<Unit>::operator=(const ActiveTail<Unit>& that) { //self assignment is safe in this case tailp_ = that.tailp_; otherTailp_ = that.otherTailp_; polyLineSize_ = that.polyLineSize_; return *this; } template <typename Unit> inline bool ActiveTail<Unit>::operator==(const ActiveTail<Unit>& b) const { return tailp_ == b.tailp_ && otherTailp_ == b.otherTailp_; } template <typename Unit> inline bool ActiveTail<Unit>::operator<(const ActiveTail<Unit>& b) const { return tailp_->getEndPoint().get(VERTICAL) < b.tailp_->getEndPoint().get(VERTICAL); } template <typename Unit> inline bool ActiveTail<Unit>::operator<=(const ActiveTail<Unit>& b) const { return !(*this > b); } template <typename Unit> inline bool ActiveTail<Unit>::operator>(const ActiveTail<Unit>& b) const { return b < (*this); } template <typename Unit> inline bool ActiveTail<Unit>::operator>=(const ActiveTail<Unit>& b) const { return !(*this < b); } template <typename Unit> inline PolyLine<Unit>* ActiveTail<Unit>::getTail() const { return tailp_; } template <typename Unit> inline PolyLine<Unit>* ActiveTail<Unit>::getOtherTail() const { return otherTailp_->tailp_; } template <typename Unit> inline ActiveTail<Unit>* ActiveTail<Unit>::getOtherActiveTail() const { return otherTailp_; } template <typename Unit> inline bool ActiveTail<Unit>::isOtherTail(const ActiveTail<Unit>& b) { // assert( (tailp_ == b.getOtherTail() && getOtherTail() == b.tailp_) || // (tailp_ != b.getOtherTail() && getOtherTail() != b.tailp_)) // ("ActiveTail: Active tails out of sync"); return otherTailp_ == &b; } template <typename Unit> inline ActiveTail<Unit>& ActiveTail<Unit>::updateTail(PolyLine<Unit>* newTail) { //subtract the old size and add new size// int delta = newTail->numSegments() - tailp_->numSegments(); addPolyLineSize(delta); otherTailp_->addPolyLineSize(delta); tailp_ = newTail; return *this; } template <typename Unit> inline ActiveTail<Unit>* ActiveTail<Unit>::addHole(ActiveTail<Unit>* hole, bool fractureHoles) { if(!fractureHoles){ holesList_.push_back(hole); copyHoles(*hole); copyHoles(*(hole->getOtherActiveTail())); return this; } ActiveTail<Unit>* h, *v; ActiveTail<Unit>* other = hole->getOtherActiveTail(); if(other->getOrient() == VERTICAL) { //assert that hole.getOrient() == HORIZONTAL //this case should never happen h = hole; v = other; } else { //assert that hole.getOrient() == VERTICAL h = other; v = hole; } h->pushCoordinate(v->getCoordinate()); //assert that h->getOrient() == VERTICAL //v->pushCoordinate(getCoordinate()); //assert that v->getOrient() == VERTICAL //I can't close a figure by adding a hole, so pass zero for xMin and yMin std::vector<Unit> tmpVec; ActiveTail<Unit>::joinChains(this, h, false, tmpVec); return v; } template <typename Unit> inline const std::list<ActiveTail<Unit>*>& ActiveTail<Unit>::getHoles() const { return holesList_; } template <typename Unit> inline void ActiveTail<Unit>::copyHoles(ActiveTail<Unit>& that) { holesList_.splice(holesList_.end(), that.holesList_); //splice the two lists together } template <typename Unit> inline bool ActiveTail<Unit>::solidToRight() const { return getTail()->solidToRight(); } template <typename Unit> inline Unit ActiveTail<Unit>::getCoord() const { return getTail()->getEndCoord(); } template <typename Unit> inline Unit ActiveTail<Unit>::getCoordinate() const { return getCoord(); } template <typename Unit> inline orientation_2d ActiveTail<Unit>::getOrient() const { return getTail()->tailOrient(); } template <typename Unit> inline void ActiveTail<Unit>::pushCoordinate(Unit coord) { //appropriately handle any co-linear polyline segments by calling push point internally point_data<Unit> p; p.set(HORIZONTAL, coord); p.set(VERTICAL, coord); //if we are vertical assign the last coordinate (an X) to p.x, else to p.y p.set(getOrient().get_perpendicular(), getCoordinate()); int oldSegments = tailp_->numSegments(); tailp_->pushPoint(p); int delta = tailp_->numSegments() - oldSegments; addPolyLineSize(delta); otherTailp_->addPolyLineSize(delta); } //global utility functions template <typename Unit> inline PolyLine<Unit>* createPolyLine(orientation_2d orient, Unit coord, Side side) { return new PolyLine<Unit>(orient, coord, side); } template <typename Unit> inline void destroyPolyLine(PolyLine<Unit>* pLine) { delete pLine; } template <typename Unit> inline ActiveTail<Unit>* createActiveTail() { //consider replacing system allocator with ActiveTail memory pool return new ActiveTail<Unit>(); } template <typename Unit> inline void destroyActiveTail(ActiveTail<Unit>* aTail) { delete aTail; } //no recursion, to prevent max recursion depth errors template <typename Unit> inline void ActiveTail<Unit>::destroyContents() { tailp_->disconnectTails(); PolyLine<Unit>* nextPolyLinep = tailp_->next(HEAD); End end = tailp_->endConnectivity(HEAD); destroyPolyLine(tailp_); while(nextPolyLinep) { End nextEnd = nextPolyLinep->endConnectivity(!end); //get the direction of next polyLine PolyLine<Unit>* nextNextPolyLinep = nextPolyLinep->next(!end); //get the next polyline destroyPolyLine(nextPolyLinep); //destroy the current polyline end = nextEnd; nextPolyLinep = nextNextPolyLinep; } } template <typename Unit> inline typename ActiveTail<Unit>::iterator ActiveTail<Unit>::begin(bool isHole, orientation_2d orient) const { return iterator(this, isHole, orient); } template <typename Unit> inline typename ActiveTail<Unit>::iterator ActiveTail<Unit>::end() const { return iterator(); } template <typename Unit> inline typename ActiveTail<Unit>::iteratorHoles ActiveTail<Unit>::beginHoles() const { return holesList_.begin(); } template <typename Unit> inline typename ActiveTail<Unit>::iteratorHoles ActiveTail<Unit>::endHoles() const { return holesList_.end(); } template <typename Unit> inline void ActiveTail<Unit>::writeOutFigureItrs(iterator& beginOut, iterator& endOut, bool isHole, orientation_2d orient) const { beginOut = begin(isHole, orient); endOut = end(); } template <typename Unit> inline void ActiveTail<Unit>::writeOutFigureHoleItrs(iteratorHoles& beginOut, iteratorHoles& endOut) const { beginOut = beginHoles(); endOut = endHoles(); } template <typename Unit> inline void ActiveTail<Unit>::writeOutFigure(std::vector<Unit>& outVec, bool isHole) const { //we start writing out the polyLine that this active tail points to at its tail std::size_t size = outVec.size(); outVec.push_back(0); //place holder for size PolyLine<Unit>* nextPolyLinep = 0; if(!isHole){ nextPolyLinep = otherTailp_->tailp_->writeOut(outVec); } else { nextPolyLinep = tailp_->writeOut(outVec); } Unit firsty = outVec[size + 1]; if((getOrient() == HORIZONTAL) ^ !isHole) { //our first coordinate is a y value, so we need to rotate it to the end typename std::vector<Unit>::iterator tmpItr = outVec.begin(); tmpItr += size; outVec.erase(++tmpItr); //erase the 2nd element } End startEnd = tailp_->endConnectivity(HEAD); if(isHole) startEnd = otherTailp_->tailp_->endConnectivity(HEAD); while(nextPolyLinep) { bool nextStartEnd = nextPolyLinep->endConnectivity(!startEnd); nextPolyLinep = nextPolyLinep->writeOut(outVec, startEnd); startEnd = nextStartEnd; } if((getOrient() == HORIZONTAL) ^ !isHole) { //we want to push the y value onto the end since we ought to have ended with an x outVec.push_back(firsty); //should never be executed because we want first value to be an x } //the vector contains the coordinates of the linked list of PolyLines in the correct order //first element is supposed to be the size outVec[size] = outVec.size() - 1 - size; //number of coordinates in vector //assert outVec[size] % 2 == 0 //it should be even //make the size negative for holes outVec[size] *= (isHole ? -1 : 1); } //no recursion to prevent max recursion depth errors template <typename Unit> inline PolyLine<Unit>* PolyLine<Unit>::writeOut(std::vector<Unit>& outVec, End startEnd) const { if(startEnd == HEAD){ //forward order outVec.insert(outVec.end(), ptdata_.begin(), ptdata_.end()); return tailp_; }else{ //reverse order //do not reserve because we expect outVec to be large enough already for(int i = ptdata_.size() - 1; i >= 0; --i){ outVec.push_back(ptdata_[i]); } //NT didn't know about this version of the API.... //outVec.insert(outVec.end(), ptdata_.rbegin(), ptdata_.rend()); return headp_; } } //solid indicates if it was joined by a solit or a space template <typename Unit> inline ActiveTail<Unit>* ActiveTail<Unit>::joinChains(ActiveTail<Unit>* at1, ActiveTail<Unit>* at2, bool solid, std::vector<Unit>& outBufferTmp) { //checks to see if we closed a figure if(at1->isOtherTail(*at2)){ //value of solid tells us if we closed solid or hole //and output the solid or handle the hole appropriately //if the hole needs to fracture across horizontal partition boundary we need to notify //the calling context to do so if(solid) { //the chains are being joined because there is solid to the right //this means that if the figure is closed at this point it must be a hole //because otherwise it would have to have another vertex to the right of this one //and would not be closed at this point return at1; } else { //assert pG != 0 //the figure that was closed is a shell at1->writeOutFigure(outBufferTmp); //process holes of the polygon at1->copyHoles(*at2); //there should not be holes on at2, but if there are, copy them over const std::list<ActiveTail<Unit>*>& holes = at1->getHoles(); for(typename std::list<ActiveTail<Unit>*>::const_iterator litr = holes.begin(); litr != holes.end(); ++litr) { (*litr)->writeOutFigure(outBufferTmp, true); //delete the hole (*litr)->destroyContents(); destroyActiveTail((*litr)->getOtherActiveTail()); destroyActiveTail((*litr)); } //delete the polygon at1->destroyContents(); //at2 contents are the same as at1, so it should not destroy them destroyActiveTail(at1); destroyActiveTail(at2); } return 0; } //join the two partial polygons into one large partial polygon at1->getTail()->joinTailToTail(*(at2->getTail())); *(at1->getOtherActiveTail()) = ActiveTail(at1->getOtherTail(), at2->getOtherActiveTail()); *(at2->getOtherActiveTail()) = ActiveTail(at2->getOtherTail(), at1->getOtherActiveTail()); int accumulate = at2->getPolyLineSize() + at1->getPolyLineSize(); (at1->getOtherActiveTail())->setPolyLineSize(accumulate); (at2->getOtherActiveTail())->setPolyLineSize(accumulate); at1->getOtherActiveTail()->copyHoles(*at1); at1->getOtherActiveTail()->copyHoles(*at2); destroyActiveTail(at1); destroyActiveTail(at2); return 0; } //solid indicates if it was joined by a solit or a space template <typename Unit> template <typename PolygonT> inline ActiveTail<Unit>* ActiveTail<Unit>::joinChains(ActiveTail<Unit>* at1, ActiveTail<Unit>* at2, bool solid, std::vector<PolygonT>& outBufferTmp) { //checks to see if we closed a figure if(at1->isOtherTail(*at2)){ //value of solid tells us if we closed solid or hole //and output the solid or handle the hole appropriately //if the hole needs to fracture across horizontal partition boundary we need to notify //the calling context to do so if(solid) { //the chains are being joined because there is solid to the right //this means that if the figure is closed at this point it must be a hole //because otherwise it would have to have another vertex to the right of this one //and would not be closed at this point return at1; } else { //assert pG != 0 //the figure that was closed is a shell outBufferTmp.push_back(at1); at1->copyHoles(*at2); //there should not be holes on at2, but if there are, copy them over } return 0; } //join the two partial polygons into one large partial polygon at1->getTail()->joinTailToTail(*(at2->getTail())); *(at1->getOtherActiveTail()) = ActiveTail<Unit>(at1->getOtherTail(), at2->getOtherActiveTail()); *(at2->getOtherActiveTail()) = ActiveTail<Unit>(at2->getOtherTail(), at1->getOtherActiveTail()); int accumulate = at2->getPolyLineSize() + at1->getPolyLineSize(); (at1->getOtherActiveTail())->setPolyLineSize(accumulate); (at2->getOtherActiveTail())->setPolyLineSize(accumulate); at1->getOtherActiveTail()->copyHoles(*at1); at1->getOtherActiveTail()->copyHoles(*at2); destroyActiveTail(at1); destroyActiveTail(at2); return 0; } template <class TKey, class T> inline typename std::map<TKey, T>::iterator findAtNext(std::map<TKey, T>& theMap, typename std::map<TKey, T>::iterator pos, const TKey& key) { if(pos == theMap.end()) return theMap.find(key); //if they match the mapItr is pointing to the correct position if(pos->first < key) { return theMap.find(key); } if(pos->first > key) { return theMap.end(); } //else they are equal and no need to do anything to the iterator return pos; } // createActiveTailsAsPair is called in these two end cases of geometry // 1. lower left concave corner // ###| // ###| // ###|### // ###|### // 2. lower left convex corner // |### // |### // | // | // In case 1 there may be a hole propigated up from the bottom. If the fracture option is enabled // the two active tails that form the filament fracture line edges can become the new active tail pair // by pushing x and y onto them. Otherwise the hole simply needs to be associated to one of the new active tails // with add hole template <typename Unit> inline std::pair<ActiveTail<Unit>*, ActiveTail<Unit>*> createActiveTailsAsPair(Unit x, Unit y, bool solid, ActiveTail<Unit>* phole, bool fractureHoles) { ActiveTail<Unit>* at1 = 0; ActiveTail<Unit>* at2 = 0; if(!phole || !fractureHoles){ at1 = createActiveTail<Unit>(); at2 = createActiveTail<Unit>(); (*at1) = ActiveTail<Unit>(VERTICAL, x, solid, at2); (*at2) = ActiveTail<Unit>(HORIZONTAL, y, !solid, at1); //provide a function through activeTail class to provide this at1->getTail()->joinHeadToHead(*(at2->getTail())); at1->addPolyLineSize(1); at2->addPolyLineSize(1); if(phole) at1->addHole(phole, fractureHoles); //assert fractureHoles == false return std::pair<ActiveTail<Unit>*, ActiveTail<Unit>*>(at1, at2); } //assert phole is not null //assert fractureHoles is true if(phole->getOrient() == VERTICAL) { at2 = phole; } else { at2 = phole->getOtherActiveTail(); //should never be executed since orientation is expected to be vertical } //assert solid == false, we should be creating a corner with solid below and to the left if there was a hole at1 = at2->getOtherActiveTail(); //assert at1 is horizontal at1->pushCoordinate(x); //assert at2 is vertical at2->pushCoordinate(y); return std::pair<ActiveTail<Unit>*, ActiveTail<Unit>*>(at1, at2); } /* * | * | * = * |######## * |######## (add a new ActiveTail in the tailMap_). * |######## * |######## * |######## * = * | * | * * NOTE: Call this only if you are sure that the $ledege$ is not in the tailMap_ */ template<bool orientT, typename Unit, typename polygon_concept_type> inline void ScanLineToPolygonItrs<orientT, Unit, polygon_concept_type>:: insertNewLeftEdgeIntoTailMap(Unit currentX, Unit yBegin, Unit yEnd, typename std::map<Unit, ActiveTail<Unit> *>::iterator &hint){ ActiveTail<Unit> *currentTail = NULL; std::pair<ActiveTail<Unit>*, ActiveTail<Unit>*> tailPair = createActiveTailsAsPair(currentX, yBegin, true, currentTail, fractureHoles_); currentTail = tailPair.first; if(!tailMap_.empty()){ ++hint; } hint = tailMap_.insert(hint, std::make_pair(yBegin, tailPair.second)); currentTail->pushCoordinate(yEnd); ++hint; hint = tailMap_.insert(hint, std::make_pair(yEnd, currentTail)); } template<bool orientT, typename Unit, typename polygon_concept_type> inline void ScanLineToPolygonItrs<orientT, Unit, polygon_concept_type>:: closePartialSimplePolygon(Unit currentX, ActiveTail<Unit>*pfig, ActiveTail<Unit>*ppfig){ pfig->pushCoordinate(currentX); ActiveTail<Unit>::joinChains(pfig, ppfig, false, outputPolygons_); } /* * If the invariant is maintained correctly then left edges can do the * following. * * =### * ####### * ####### * ####### * ####### * =### * |### (input left edge) * |### * =### * ####### * ####### * =### */ template<bool orientT, typename Unit, typename polygon_concept_type> inline void ScanLineToPolygonItrs<orientT, Unit, polygon_concept_type>:: updatePartialSimplePolygonsWithLeftEdges(Unit currentX, const std::vector<interval_data<Unit> > &leftEdges, size_t vertexThreshold){ typename std::map<Unit, ActiveTail<Unit>* >::iterator succ, succ1; typename std::map<Unit, ActiveTail<Unit>* >::iterator pred, pred1, hint; Unit begin, end; ActiveTail<Unit> *pfig, *ppfig; std::pair<ActiveTail<Unit>*, ActiveTail<Unit>*> tailPair; size_t pfig_size = 0; hint = tailMap_.begin(); for(size_t i=0; i < leftEdges.size(); i++){ begin = leftEdges[i].get(LOW); end = leftEdges[i].get(HIGH); succ = findAtNext(tailMap_, hint, begin); pred = findAtNext(tailMap_, hint, end); if(succ != tailMap_.end() && pred != tailMap_.end()){ //CASE-1// //join the corresponding active tails// pfig = succ->second; ppfig = pred->second; pfig_size = pfig->getPolyLineSize() + ppfig->getPolyLineSize(); if(pfig_size >= vertexThreshold){ size_t bsize = pfig->getPolyLineSize(); size_t usize = ppfig->getPolyLineSize(); if(usize+2 < vertexThreshold){ //cut-off the lower piece (succ1, succ) join (succ1, pred)// succ1 = succ; --succ1; assert((succ1 != tailMap_.end()) && ((succ->second)->getOtherActiveTail() == succ1->second)); closePartialSimplePolygon(currentX, succ1->second, succ->second); tailPair = createActiveTailsAsPair<Unit>(currentX, succ1->first, true, NULL, fractureHoles_); //just update the succ1 with new ActiveTail<Unit>*// succ1->second = tailPair.second; ActiveTail<Unit>::joinChains(tailPair.first, pred->second, true, outputPolygons_); }else if(bsize+2 < vertexThreshold){ //cut-off the upper piece () join ()// pred1 = pred; ++pred1; assert(pred1 != tailMap_.end() && ((pred1->second)->getOtherActiveTail() == pred->second)); closePartialSimplePolygon(currentX, pred->second, pred1->second); //just update the pred1 with ActiveTail<Unit>* = pfig// pred1->second = pfig; pfig->pushCoordinate(currentX); pfig->pushCoordinate(pred1->first); }else{ //cut both and create an left edge between (pred->first, succ1)// succ1 = succ; --succ1; pred1 = pred; ++pred1; assert(pred1 != tailMap_.end() && succ1 != tailMap_.end()); assert((pred1->second)->getOtherActiveTail() == pred->second); assert((succ1->second)->getOtherActiveTail() == succ->second); closePartialSimplePolygon(currentX, succ1->second, succ->second); closePartialSimplePolygon(currentX, pred->second, pred1->second); tailPair = createActiveTailsAsPair<Unit>(currentX, succ1->first, true, NULL, fractureHoles_); succ1->second = tailPair.second; pred1->second = tailPair.first; (tailPair.first)->pushCoordinate(pred1->first); } }else{ //just join them with closing// pfig->pushCoordinate(currentX); ActiveTail<Unit>::joinChains(pfig, ppfig, true, outputPolygons_); } hint = pred; ++hint; tailMap_.erase(succ); tailMap_.erase(pred); }else if(succ == tailMap_.end() && pred != tailMap_.end()){ //CASE-2// //succ is missing in the map, first insert it into the map// tailPair = createActiveTailsAsPair<Unit>(currentX, begin, true, NULL, fractureHoles_); hint = pred; ++hint; hint = tailMap_.insert(hint, std::make_pair(begin, tailPair.second)); pfig = pred->second; pfig_size = pfig->getPolyLineSize() + 2; if(pfig_size >= vertexThreshold){ //cut-off piece from [pred, pred1] , add [begin, pred1]// pred1 = pred; ++pred1; assert((pred1 != tailMap_.end()) && ((pred1->second)->getOtherActiveTail() == pred->second)); closePartialSimplePolygon(currentX, pred->second, pred1->second); //update: we need left edge between (begin, pred1->first)// pred1->second = tailPair.first; (tailPair.first)->pushCoordinate(pred1->first); }else{ //just join// ActiveTail<Unit>::joinChains(tailPair.first, pfig, true, outputPolygons_); } tailMap_.erase(pred); }else if(succ != tailMap_.end() && pred == tailMap_.end()){ //CASE-3// //pred is missing in the map, first insert it into the map// hint = succ; ++hint; hint = tailMap_.insert(hint, std::make_pair(end, (ActiveTail<Unit> *) NULL)); pfig = succ->second; pfig_size = pfig->getPolyLineSize() + 2; if(pfig_size >= vertexThreshold){ //this figure needs cutting here// succ1 = succ; --succ1; assert((succ1 != tailMap_.end()) && (succ1->second == pfig->getOtherActiveTail())); ppfig = succ1->second; closePartialSimplePolygon(currentX, ppfig, pfig); //update: we need a left edge between (succ1->first, end)// tailPair = createActiveTailsAsPair<Unit>(currentX, succ1->first, true, NULL, fractureHoles_); succ1->second = tailPair.second; hint->second = tailPair.first; (tailPair.first)->pushCoordinate(end); }else{ //no cutting needed// hint->second = pfig; pfig->pushCoordinate(currentX); pfig->pushCoordinate(end); } tailMap_.erase(succ); }else{ //insert both pred and succ// insertNewLeftEdgeIntoTailMap(currentX, begin, end, hint); } } } template<bool orientT, typename Unit, typename polygon_concept_type> inline void ScanLineToPolygonItrs<orientT, Unit, polygon_concept_type>:: updatePartialSimplePolygonsWithRightEdges(Unit currentX, const std::vector<interval_data<Unit> > &rightEdges, size_t vertexThreshold) { typename std::map<Unit, ActiveTail<Unit>* >::iterator succ, pred, hint; std::pair<ActiveTail<Unit>*, ActiveTail<Unit>*> tailPair; Unit begin, end; size_t i = 0; //If rightEdges is non-empty Then tailMap_ is non-empty // assert(rightEdges.empty() || !tailMap_.empty() ); while( i < rightEdges.size() ){ //find the interval in the tailMap which contains this interval// pred = tailMap_.lower_bound(rightEdges[i].get(HIGH)); assert(pred != tailMap_.end()); succ = pred; --succ; assert(pred != succ); end = pred->first; begin = succ->first; //we now have a [begin, end] // bool found_solid_opening = false; bool erase_succ = true, erase_pred = true; Unit solid_opening_begin = 0; Unit solid_opening_end = 0; size_t j = i+1; ActiveTail<Unit> *pfig = succ->second; ActiveTail<Unit> *ppfig = pred->second; size_t partial_fig_size = pfig->getPolyLineSize(); //Invariant:// assert(succ->second && (pfig)->getOtherActiveTail() == ppfig); hint = succ; Unit key = rightEdges[i].get(LOW); if(begin != key){ found_solid_opening = true; solid_opening_begin = begin; solid_opening_end = key; } while(j < rightEdges.size() && rightEdges[j].get(HIGH) <= end){ if(rightEdges[j-1].get(HIGH) != rightEdges[j].get(LOW)){ if(!found_solid_opening){ found_solid_opening = true; solid_opening_begin = rightEdges[j-1].get(HIGH); solid_opening_end = rightEdges[j].get(LOW); }else{ ++hint; insertNewLeftEdgeIntoTailMap(currentX, rightEdges[j-1].get(HIGH), rightEdges[j].get(LOW), hint); } } j++; } //trailing edge// if(end != rightEdges[j-1].get(HIGH)){ if(!found_solid_opening){ found_solid_opening = true; solid_opening_begin = rightEdges[j-1].get(HIGH); solid_opening_end = end; }else{ // a solid opening has been found already, we need to insert a new left // between [rightEdges[j-1].get(HIGH), end] Unit lbegin = rightEdges[j-1].get(HIGH); tailPair = createActiveTailsAsPair<Unit>(currentX, lbegin, true, NULL, fractureHoles_); hint = tailMap_.insert(pred, std::make_pair(lbegin, tailPair.second)); pred->second = tailPair.first; (tailPair.first)->pushCoordinate(end); erase_pred = false; } } size_t vertex_delta = ((begin != solid_opening_begin) && (end != solid_opening_end)) ? 4 : 2; if(!found_solid_opening){ //just close the figure, TODO: call closePartialPolygon// pfig->pushCoordinate(currentX); ActiveTail<Unit>::joinChains(pfig, ppfig, false, outputPolygons_); hint = pred; ++hint; }else if(partial_fig_size+vertex_delta >= vertexThreshold){ //close the figure and add a pseudo left-edge// closePartialSimplePolygon(currentX, pfig, ppfig); assert(begin != solid_opening_begin || end != solid_opening_end); if(begin != solid_opening_begin && end != solid_opening_end){ insertNewLeftEdgeIntoTailMap(currentX, solid_opening_begin, solid_opening_end, hint); }else if(begin == solid_opening_begin){ //we just need to update the succ in the tailMap_// tailPair = createActiveTailsAsPair<Unit>(currentX, solid_opening_begin, true, NULL, fractureHoles_); succ->second = tailPair.second; hint = succ; ++hint; hint = tailMap_.insert(pred, std::make_pair(solid_opening_end, tailPair.first)); (tailPair.first)->pushCoordinate(solid_opening_end); erase_succ = false; }else{ //we just need to update the pred in the tailMap_// tailPair = createActiveTailsAsPair<Unit>(currentX, solid_opening_begin, true, NULL, fractureHoles_); hint = tailMap_.insert(pred, std::make_pair(solid_opening_begin, tailPair.second)); pred->second = tailPair.first; (tailPair.first)->pushCoordinate(solid_opening_end); erase_pred = false; } }else{ //continue the figure (by adding at-most two new vertices)// if(begin != solid_opening_begin){ pfig->pushCoordinate(currentX); pfig->pushCoordinate(solid_opening_begin); //insert solid_opening_begin// hint = succ; ++hint; hint = tailMap_.insert(hint, std::make_pair(solid_opening_begin, pfig)); }else{ erase_succ = false; } if(end != solid_opening_end){ std::pair<ActiveTail<Unit>*, ActiveTail<Unit>*> tailPair = createActiveTailsAsPair<Unit>(currentX, solid_opening_end, false, NULL, fractureHoles_); hint = pred; ++hint; hint = tailMap_.insert(hint, std::make_pair(solid_opening_end, tailPair.second)); ActiveTail<Unit>::joinChains(tailPair.first, ppfig, false, outputPolygons_); }else{ erase_pred = false; } } //Remove the pred and succ if necessary// if(erase_succ){ tailMap_.erase(succ); } if(erase_pred){ tailMap_.erase(pred); } i = j; } } // Maintains the following invariant: // a. All the partial polygons formed at any state can be closed // by a single edge. template<bool orientT, typename Unit, typename polygon_concept_type> inline void ScanLineToPolygonItrs<orientT, Unit, polygon_concept_type>:: maintainPartialSimplePolygonInvariant(iterator& beginOutput, iterator& endOutput, Unit currentX, const std::vector<interval_data<Unit> >& l, const std::vector<interval_data<Unit> >& r, size_t vertexThreshold) { clearOutput_(); if(!l.empty()){ updatePartialSimplePolygonsWithLeftEdges(currentX, l, vertexThreshold); } if(!r.empty()){ updatePartialSimplePolygonsWithRightEdges(currentX, r, vertexThreshold); } beginOutput = outputPolygons_.begin(); endOutput = outputPolygons_.end(); } //Process edges connects vertical input edges (right or left edges of figures) to horizontal edges stored as member //data of the scanline object. It also creates now horizontal edges as needed to construct figures from edge data. // //There are only 12 geometric end cases where the scanline intersects a horizontal edge and even fewer unique //actions to take: // 1. Solid on both sides of the vertical partition after the current position and space on both sides before // ###|### // ###|### // | // | // This case does not need to be handled because there is no vertical edge at the current x coordinate. // // 2. Solid on both sides of the vertical partition before the current position and space on both sides after // | // | // ###|### // ###|### // This case does not need to be handled because there is no vertical edge at the current x coordinate. // // 3. Solid on the left of the vertical partition after the current position and space elsewhere // ###| // ###| // | // | // The horizontal edge from the left is found and turns upward because of the vertical right edge to become // the currently active vertical edge. // // 4. Solid on the left of the vertical partion before the current position and space elsewhere // | // | // ###| // ###| // The horizontal edge from the left is found and joined to the currently active vertical edge. // // 5. Solid to the right above and below and solid to the left above current position. // ###|### // ###|### // |### // |### // The horizontal edge from the left is found and joined to the currently active vertical edge, // potentially closing a hole. // // 6. Solid on the left of the vertical partion before the current position and solid to the right above and below // |### // |### // ###|### // ###|### // The horizontal edge from the left is found and turns upward because of the vertical right edge to become // the currently active vertical edge. // // 7. Solid on the right of the vertical partition after the current position and space elsewhere // |### // |### // | // | // Create two new ActiveTails, one is added to the horizontal edges and the other becomes the vertical currentTail // // 8. Solid on the right of the vertical partion before the current position and space elsewhere // | // | // |### // |### // The currentTail vertical edge turns right and is added to the horizontal edges data // // 9. Solid to the right above and solid to the left above and below current position. // ###|### // ###|### // ###| // ###| // The currentTail vertical edge turns right and is added to the horizontal edges data // // 10. Solid on the left of the vertical partion above and below the current position and solid to the right below // ###| // ###| // ###|### // ###|### // Create two new ActiveTails, one is added to the horizontal edges data and the other becomes the vertical currentTail // // 11. Solid to the right above and solid to the left below current position. // |### // |### // ###| // ###| // The currentTail vertical edge joins the horizontal edge from the left (may close a polygon) // Create two new ActiveTails, one is added to the horizontal edges data and the other becomes the vertical currentTail // // 12. Solid on the left of the vertical partion above the current position and solid to the right below // ###| // ###| // |### // |### // The currentTail vertical edge turns right and is added to the horizontal edges data. // The horizontal edge from the left turns upward and becomes the currentTail vertical edge // template <bool orientT, typename Unit, typename polygon_concept_type> inline void ScanLineToPolygonItrs<orientT, Unit, polygon_concept_type>:: processEdges(iterator& beginOutput, iterator& endOutput, Unit currentX, std::vector<interval_data<Unit> >& leftEdges, std::vector<interval_data<Unit> >& rightEdges, size_t vertexThreshold) { clearOutput_(); typename std::map<Unit, ActiveTail<Unit>*>::iterator nextMapItr; //foreach edge unsigned int leftIndex = 0; unsigned int rightIndex = 0; bool bottomAlreadyProcessed = false; ActiveTail<Unit>* currentTail = 0; const Unit UnitMax = (std::numeric_limits<Unit>::max)(); if(vertexThreshold < (std::numeric_limits<size_t>::max)()){ maintainPartialSimplePolygonInvariant(beginOutput, endOutput, currentX, leftEdges, rightEdges, vertexThreshold); return; } nextMapItr = tailMap_.begin(); while(leftIndex < leftEdges.size() || rightIndex < rightEdges.size()) { interval_data<Unit> edges[2] = {interval_data<Unit> (UnitMax, UnitMax), interval_data<Unit> (UnitMax, UnitMax)}; bool haveNextEdge = true; if(leftIndex < leftEdges.size()) edges[0] = leftEdges[leftIndex]; else haveNextEdge = false; if(rightIndex < rightEdges.size()) edges[1] = rightEdges[rightIndex]; else haveNextEdge = false; bool trailingEdge = edges[1].get(LOW) < edges[0].get(LOW); interval_data<Unit> & edge = edges[trailingEdge]; interval_data<Unit> & nextEdge = edges[!trailingEdge]; //process this edge if(!bottomAlreadyProcessed) { //assert currentTail = 0 //process the bottom end of this edge typename std::map<Unit, ActiveTail<Unit>*>::iterator thisMapItr = findAtNext(tailMap_, nextMapItr, edge.get(LOW)); if(thisMapItr != tailMap_.end()) { //there is an edge in the map at the low end of this edge //it needs to turn upward and become the current tail ActiveTail<Unit>* tail = thisMapItr->second; if(currentTail) { //stitch currentTail into this tail currentTail = tail->addHole(currentTail, fractureHoles_); if(!fractureHoles_) currentTail->pushCoordinate(currentX); } else { currentTail = tail; currentTail->pushCoordinate(currentX); } //assert currentTail->getOrient() == VERTICAL nextMapItr = thisMapItr; //set nextMapItr to the next position after this one ++nextMapItr; //remove thisMapItr from the map tailMap_.erase(thisMapItr); } else { //there is no edge in the map at the low end of this edge //we need to create one and another one to be the current vertical tail //if this is a trailing edge then there is space to the right of the vertical edge //so pass the inverse of trailingEdge to indicate solid to the right std::pair<ActiveTail<Unit>*, ActiveTail<Unit>*> tailPair = createActiveTailsAsPair(currentX, edge.get(LOW), !trailingEdge, currentTail, fractureHoles_); currentTail = tailPair.first; tailMap_.insert(nextMapItr, std::pair<Unit, ActiveTail<Unit>*>(edge.get(LOW), tailPair.second)); // leave nextMapItr unchanged } } if(haveNextEdge && edge.get(HIGH) == nextEdge.get(LOW)) { //the top of this edge is equal to the bottom of the next edge, process them both bottomAlreadyProcessed = true; typename std::map<Unit, ActiveTail<Unit>*>::iterator thisMapItr = findAtNext(tailMap_, nextMapItr, edge.get(HIGH)); if(thisMapItr == tailMap_.end()) //assert this should never happen return; if(trailingEdge) { //geometry at this position // |## // |## // ----- // ##| // ##| //current tail should join thisMapItr tail ActiveTail<Unit>* tail = thisMapItr->second; //pass false because they are being joined because space is to the right and it will close a solid figure ActiveTail<Unit>::joinChains(currentTail, tail, false, outputPolygons_); //two new tails are created, the vertical becomes current tail, the horizontal becomes thisMapItr tail //pass true becuase they are created at the lower left corner of some solid //pass null because there is no hole pointer possible std::pair<ActiveTail<Unit>*, ActiveTail<Unit>*> tailPair = createActiveTailsAsPair<Unit>(currentX, edge.get(HIGH), true, 0, fractureHoles_); currentTail = tailPair.first; thisMapItr->second = tailPair.second; } else { //geometry at this position // ##| // ##| // ----- // |## // |## //current tail should turn right currentTail->pushCoordinate(edge.get(HIGH)); //thisMapItr tail should turn up thisMapItr->second->pushCoordinate(currentX); //thisMapItr tail becomes current tail and current tail becomes thisMapItr tail std::swap(currentTail, thisMapItr->second); } nextMapItr = thisMapItr; //set nextMapItr to the next position after this one ++nextMapItr; } else { //there is a gap between the top of this edge and the bottom of the next, process the top of this edge bottomAlreadyProcessed = false; //process the top of this edge typename std::map<Unit, ActiveTail<Unit>*>::iterator thisMapItr = findAtNext(tailMap_, nextMapItr, edge.get(HIGH)); if(thisMapItr != tailMap_.end()) { //thisMapItr is pointing to a horizontal edge in the map at the top of this vertical edge //we need to join them and potentially close a figure //assert currentTail != 0 ActiveTail<Unit>* tail = thisMapItr->second; //pass the opositve of trailing edge to mean that they are joined because of solid to the right currentTail = ActiveTail<Unit>::joinChains(currentTail, tail, !trailingEdge, outputPolygons_); nextMapItr = thisMapItr; //set nextMapItr to the next position after this one ++nextMapItr; if(currentTail) { //figure is not closed// Unit nextItrY = UnitMax; if(nextMapItr != tailMap_.end()) { nextItrY = nextMapItr->first; } //for it to be a hole this must have been a left edge Unit leftY = UnitMax; if(leftIndex + 1 < leftEdges.size()) leftY = leftEdges[leftIndex+1].get(LOW); Unit rightY = nextEdge.get(LOW); if(!haveNextEdge || (nextItrY < leftY && nextItrY < rightY)) { //we need to add it to the next edge above it in the map tail = nextMapItr->second; tail = tail->addHole(currentTail, fractureHoles_); if(fractureHoles_) { //some small additional work stitching in the filament tail->pushCoordinate(nextItrY); nextMapItr->second = tail; } //set current tail to null currentTail = 0; } } //delete thisMapItr from the map tailMap_.erase(thisMapItr); } else { //currentTail must turn right and be added into the map currentTail->pushCoordinate(edge.get(HIGH)); //assert currentTail->getOrient() == HORIZONTAL tailMap_.insert(nextMapItr, std::pair<Unit, ActiveTail<Unit>*>(edge.get(HIGH), currentTail)); //set currentTail to null currentTail = 0; //leave nextMapItr unchanged, it is still next } } //increment index leftIndex += !trailingEdge; rightIndex += trailingEdge; } //end while beginOutput = outputPolygons_.begin(); endOutput = outputPolygons_.end(); } //end function template<bool orientT, typename Unit, typename polygon_concept_type> inline void ScanLineToPolygonItrs<orientT, Unit, polygon_concept_type>::clearOutput_() { for(std::size_t i = 0; i < outputPolygons_.size(); ++i) { ActiveTail<Unit>* at1 = outputPolygons_[i].yield(); const std::list<ActiveTail<Unit>*>& holes = at1->getHoles(); for(typename std::list<ActiveTail<Unit>*>::const_iterator litr = holes.begin(); litr != holes.end(); ++litr) { //delete the hole (*litr)->destroyContents(); destroyActiveTail((*litr)->getOtherActiveTail()); destroyActiveTail((*litr)); } //delete the polygon at1->destroyContents(); //at2 contents are the same as at1, so it should not destroy them destroyActiveTail((at1)->getOtherActiveTail()); destroyActiveTail(at1); } outputPolygons_.clear(); } } //polygon_formation namespace template <bool orientT, typename Unit> struct geometry_concept<polygon_formation::PolyLinePolygonWithHolesData<orientT, Unit> > { typedef polygon_90_with_holes_concept type; }; template <bool orientT, typename Unit> struct geometry_concept<polygon_formation::PolyLineHoleData<orientT, Unit> > { typedef polygon_90_concept type; }; //public API to access polygon formation algorithm template <typename output_container, typename iterator_type, typename concept_type> unsigned int get_polygons(output_container& container, iterator_type begin, iterator_type end, orientation_2d orient, bool fracture_holes, concept_type, size_t sliceThreshold = (std::numeric_limits<size_t>::max)() ) { typedef typename output_container::value_type polygon_type; typedef typename std::iterator_traits<iterator_type>::value_type::first_type coordinate_type; polygon_type poly; unsigned int countPolygons = 0; typedef typename geometry_concept<polygon_type>::type polygon_concept_type; polygon_formation::ScanLineToPolygonItrs<true, coordinate_type, polygon_concept_type> scanlineToPolygonItrsV(fracture_holes); polygon_formation::ScanLineToPolygonItrs<false, coordinate_type, polygon_concept_type> scanlineToPolygonItrsH(fracture_holes); std::vector<interval_data<coordinate_type> > leftEdges; std::vector<interval_data<coordinate_type> > rightEdges; coordinate_type prevPos = (std::numeric_limits<coordinate_type>::max)(); coordinate_type prevY = (std::numeric_limits<coordinate_type>::max)(); int count = 0; for(iterator_type itr = begin; itr != end; ++ itr) { coordinate_type pos = (*itr).first; if(pos != prevPos) { if(orient == VERTICAL) { typename polygon_formation::ScanLineToPolygonItrs<true, coordinate_type, polygon_concept_type>::iterator itrPoly, itrPolyEnd; scanlineToPolygonItrsV.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges, sliceThreshold); for( ; itrPoly != itrPolyEnd; ++ itrPoly) { ++countPolygons; assign(poly, *itrPoly); container.insert(container.end(), poly); } } else { typename polygon_formation::ScanLineToPolygonItrs<false, coordinate_type, polygon_concept_type>::iterator itrPoly, itrPolyEnd; scanlineToPolygonItrsH.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges, sliceThreshold); for( ; itrPoly != itrPolyEnd; ++ itrPoly) { ++countPolygons; assign(poly, *itrPoly); container.insert(container.end(), poly); } } leftEdges.clear(); rightEdges.clear(); prevPos = pos; prevY = (*itr).second.first; count = (*itr).second.second; continue; } coordinate_type y = (*itr).second.first; if(count != 0 && y != prevY) { std::pair<interval_data<coordinate_type>, int> element(interval_data<coordinate_type>(prevY, y), count); if(element.second == 1) { if(leftEdges.size() && leftEdges.back().high() == element.first.low()) { encompass(leftEdges.back(), element.first); } else { leftEdges.push_back(element.first); } } else { if(rightEdges.size() && rightEdges.back().high() == element.first.low()) { encompass(rightEdges.back(), element.first); } else { rightEdges.push_back(element.first); } } } prevY = y; count += (*itr).second.second; } if(orient == VERTICAL) { typename polygon_formation::ScanLineToPolygonItrs<true, coordinate_type, polygon_concept_type>::iterator itrPoly, itrPolyEnd; scanlineToPolygonItrsV.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges, sliceThreshold); for( ; itrPoly != itrPolyEnd; ++ itrPoly) { ++countPolygons; assign(poly, *itrPoly); container.insert(container.end(), poly); } } else { typename polygon_formation::ScanLineToPolygonItrs<false, coordinate_type, polygon_concept_type>::iterator itrPoly, itrPolyEnd; scanlineToPolygonItrsH.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges, sliceThreshold); for( ; itrPoly != itrPolyEnd; ++ itrPoly) { ++countPolygons; assign(poly, *itrPoly); container.insert(container.end(), poly); } } return countPolygons; } } } #endif detail/iterator_points_to_compact.hpp 0000644 00000004033 15125572616 0014166 0 ustar 00 /* 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_ITERATOR_POINTS_TO_COMPACT_HPP #define BOOST_POLYGON_ITERATOR_POINTS_TO_COMPACT_HPP namespace boost { namespace polygon{ template <typename iT, typename point_type> class iterator_points_to_compact { private: iT iter_, iterEnd_; orientation_2d orient_; mutable typename point_traits<point_type>::coordinate_type coord_; public: typedef typename point_traits<point_type>::coordinate_type coordinate_type; typedef std::forward_iterator_tag iterator_category; typedef coordinate_type value_type; typedef std::ptrdiff_t difference_type; typedef const coordinate_type* pointer; //immutable typedef const coordinate_type& reference; //immutable inline iterator_points_to_compact() : iter_(), iterEnd_(), orient_(), coord_() {} inline iterator_points_to_compact(iT iter, iT iterEnd) : iter_(iter), iterEnd_(iterEnd), orient_(HORIZONTAL), coord_() {} inline iterator_points_to_compact(const iterator_points_to_compact& that) : iter_(that.iter_), iterEnd_(that.iterEnd_), orient_(that.orient_), coord_(that.coord_) {} //use bitwise copy and assign provided by the compiler inline iterator_points_to_compact& operator++() { //iT tmp = iter_; ++iter_; //iT tmp2 = iter_; orient_.turn_90(); //while(tmp2 != iterEnd_ && get(*tmp2, orient_) == get(*tmp, orient_)) { // iter_ = tmp2; // ++tmp2; //} return *this; } inline const iterator_points_to_compact operator++(int) { iT tmp(*this); ++(*this); return tmp; } inline bool operator==(const iterator_points_to_compact& that) const { return (iter_ == that.iter_); } inline bool operator!=(const iterator_points_to_compact& that) const { return (iter_ != that.iter_); } inline reference operator*() const { coord_ = get(*iter_, orient_); return coord_; } }; } } #endif detail/iterator_geometry_to_set.hpp 0000644 00000027462 15125572616 0013665 0 ustar 00 /* 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_ITERATOR_GEOMETRY_TO_SET_HPP #define BOOST_POLYGON_ITERATOR_GEOMETRY_TO_SET_HPP namespace boost { namespace polygon{ template <typename concept_type, typename geometry_type> class iterator_geometry_to_set {}; template <typename rectangle_type> class iterator_geometry_to_set<rectangle_concept, rectangle_type> { public: typedef typename rectangle_traits<rectangle_type>::coordinate_type coordinate_type; typedef std::forward_iterator_tag iterator_category; typedef std::pair<coordinate_type, std::pair<coordinate_type, int> > value_type; typedef std::ptrdiff_t difference_type; typedef const value_type* pointer; //immutable typedef const value_type& reference; //immutable private: rectangle_data<coordinate_type> rectangle_; mutable value_type vertex_; unsigned int corner_; orientation_2d orient_; bool is_hole_; public: iterator_geometry_to_set() : rectangle_(), vertex_(), corner_(4), orient_(), is_hole_() {} iterator_geometry_to_set(const rectangle_type& rectangle, direction_1d dir, orientation_2d orient = HORIZONTAL, bool is_hole = false, bool = false, direction_1d = CLOCKWISE) : rectangle_(), vertex_(), corner_(0), orient_(orient), is_hole_(is_hole) { assign(rectangle_, rectangle); if(dir == HIGH) corner_ = 4; } inline iterator_geometry_to_set& operator++() { ++corner_; return *this; } inline const iterator_geometry_to_set operator++(int) { iterator_geometry_to_set tmp(*this); ++(*this); return tmp; } inline bool operator==(const iterator_geometry_to_set& that) const { return corner_ == that.corner_; } inline bool operator!=(const iterator_geometry_to_set& that) const { return !(*this == that); } inline reference operator*() const { if(corner_ == 0) { vertex_.first = get(get(rectangle_, orient_.get_perpendicular()), LOW); vertex_.second.first = get(get(rectangle_, orient_), LOW); vertex_.second.second = 1; if(is_hole_) vertex_.second.second *= -1; } else if(corner_ == 1) { vertex_.second.first = get(get(rectangle_, orient_), HIGH); vertex_.second.second = -1; if(is_hole_) vertex_.second.second *= -1; } else if(corner_ == 2) { vertex_.first = get(get(rectangle_, orient_.get_perpendicular()), HIGH); vertex_.second.first = get(get(rectangle_, orient_), LOW); } else { vertex_.second.first = get(get(rectangle_, orient_), HIGH); vertex_.second.second = 1; if(is_hole_) vertex_.second.second *= -1; } return vertex_; } }; template <typename polygon_type> class iterator_geometry_to_set<polygon_90_concept, polygon_type> { public: typedef typename polygon_traits<polygon_type>::coordinate_type coordinate_type; typedef std::forward_iterator_tag iterator_category; typedef std::pair<coordinate_type, std::pair<coordinate_type, int> > value_type; typedef std::ptrdiff_t difference_type; typedef const value_type* pointer; //immutable typedef const value_type& reference; //immutable typedef typename polygon_traits<polygon_type>::iterator_type coord_iterator_type; private: value_type vertex_; typename polygon_traits<polygon_type>::iterator_type itrb, itre; bool last_vertex_; bool is_hole_; int multiplier_; point_data<coordinate_type> first_pt, second_pt, pts[3]; bool use_wrap; orientation_2d orient_; int polygon_index; public: iterator_geometry_to_set() : vertex_(), itrb(), itre(), last_vertex_(), is_hole_(), multiplier_(), first_pt(), second_pt(), pts(), use_wrap(), orient_(), polygon_index(-1) {} iterator_geometry_to_set(const polygon_type& polygon, direction_1d dir, orientation_2d orient = HORIZONTAL, bool is_hole = false, bool winding_override = false, direction_1d w = CLOCKWISE) : vertex_(), itrb(), itre(), last_vertex_(), is_hole_(is_hole), multiplier_(), first_pt(), second_pt(), pts(), use_wrap(), orient_(orient), polygon_index(0) { itrb = begin_points(polygon); itre = end_points(polygon); use_wrap = false; if(itrb == itre || dir == HIGH || ::boost::polygon::size(polygon) < 4) { polygon_index = -1; } else { direction_1d wdir = w; if(!winding_override) wdir = winding(polygon); multiplier_ = wdir == LOW ? -1 : 1; if(is_hole_) multiplier_ *= -1; first_pt = pts[0] = *itrb; ++itrb; second_pt = pts[1] = *itrb; ++itrb; pts[2] = *itrb; evaluate_(); } } iterator_geometry_to_set(const iterator_geometry_to_set& that) : vertex_(), itrb(), itre(), last_vertex_(), is_hole_(), multiplier_(), first_pt(), second_pt(), pts(), use_wrap(), orient_(), polygon_index(-1) { vertex_ = that.vertex_; itrb = that.itrb; itre = that.itre; last_vertex_ = that.last_vertex_; is_hole_ = that.is_hole_; multiplier_ = that.multiplier_; first_pt = that.first_pt; second_pt = that.second_pt; pts[0] = that.pts[0]; pts[1] = that.pts[1]; pts[2] = that.pts[2]; use_wrap = that.use_wrap; orient_ = that.orient_; polygon_index = that.polygon_index; } inline iterator_geometry_to_set& operator++() { ++polygon_index; if(itrb == itre) { if(first_pt == pts[1]) polygon_index = -1; else { pts[0] = pts[1]; pts[1] = pts[2]; if(first_pt == pts[2]) { pts[2] = second_pt; } else { pts[2] = first_pt; } } } else { ++itrb; pts[0] = pts[1]; pts[1] = pts[2]; if(itrb == itre) { if(first_pt == pts[2]) { pts[2] = second_pt; } else { pts[2] = first_pt; } } else { pts[2] = *itrb; } } evaluate_(); return *this; } inline const iterator_geometry_to_set operator++(int) { iterator_geometry_to_set tmp(*this); ++(*this); return tmp; } inline bool operator==(const iterator_geometry_to_set& that) const { return polygon_index == that.polygon_index; } inline bool operator!=(const iterator_geometry_to_set& that) const { return !(*this == that); } inline reference operator*() const { return vertex_; } inline void evaluate_() { vertex_.first = pts[1].get(orient_.get_perpendicular()); vertex_.second.first =pts[1].get(orient_); if(pts[1] == pts[2]) { vertex_.second.second = 0; } else if(pts[0].get(HORIZONTAL) != pts[1].get(HORIZONTAL)) { vertex_.second.second = -1; } else if(pts[0].get(VERTICAL) != pts[1].get(VERTICAL)) { vertex_.second.second = 1; } else { vertex_.second.second = 0; } vertex_.second.second *= multiplier_; } }; template <typename polygon_with_holes_type> class iterator_geometry_to_set<polygon_90_with_holes_concept, polygon_with_holes_type> { public: typedef typename polygon_90_traits<polygon_with_holes_type>::coordinate_type coordinate_type; typedef std::forward_iterator_tag iterator_category; typedef std::pair<coordinate_type, std::pair<coordinate_type, int> > value_type; typedef std::ptrdiff_t difference_type; typedef const value_type* pointer; //immutable typedef const value_type& reference; //immutable private: iterator_geometry_to_set<polygon_90_concept, polygon_with_holes_type> itrb, itre; iterator_geometry_to_set<polygon_90_concept, typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type> itrhib, itrhie; typename polygon_with_holes_traits<polygon_with_holes_type>::iterator_holes_type itrhb, itrhe; orientation_2d orient_; bool is_hole_; bool started_holes; public: iterator_geometry_to_set() : itrb(), itre(), itrhib(), itrhie(), itrhb(), itrhe(), orient_(), is_hole_(), started_holes() {} iterator_geometry_to_set(const polygon_with_holes_type& polygon, direction_1d dir, orientation_2d orient = HORIZONTAL, bool is_hole = false, bool = false, direction_1d = CLOCKWISE) : itrb(), itre(), itrhib(), itrhie(), itrhb(), itrhe(), orient_(orient), is_hole_(is_hole), started_holes() { itre = iterator_geometry_to_set<polygon_90_concept, polygon_with_holes_type>(polygon, HIGH, orient, is_hole_); itrhe = end_holes(polygon); if(dir == HIGH) { itrb = itre; itrhb = itrhe; started_holes = true; } else { itrb = iterator_geometry_to_set<polygon_90_concept, polygon_with_holes_type>(polygon, LOW, orient, is_hole_); itrhb = begin_holes(polygon); started_holes = false; } } iterator_geometry_to_set(const iterator_geometry_to_set& that) : itrb(), itre(), itrhib(), itrhie(), itrhb(), itrhe(), orient_(), is_hole_(), started_holes() { itrb = that.itrb; itre = that.itre; if(that.itrhib != that.itrhie) { itrhib = that.itrhib; itrhie = that.itrhie; } itrhb = that.itrhb; itrhe = that.itrhe; orient_ = that.orient_; is_hole_ = that.is_hole_; started_holes = that.started_holes; } inline iterator_geometry_to_set& operator++() { //this code can be folded with flow control factoring if(itrb == itre) { if(itrhib == itrhie) { if(itrhb != itrhe) { itrhib = iterator_geometry_to_set<polygon_90_concept, typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(*itrhb, LOW, orient_, !is_hole_); itrhie = iterator_geometry_to_set<polygon_90_concept, typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(*itrhb, HIGH, orient_, !is_hole_); ++itrhb; } else { //in this case we have no holes so we just need the iterhib == itrhie, which //is always true if they were default initialized in the initial case or //both point to end of the previous hole processed //no need to explicitly reset them, and it causes an stl debug assertion to use //the default constructed iterator this way //itrhib = itrhie = iterator_geometry_to_set<polygon_90_concept, // typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(); } } else { ++itrhib; if(itrhib == itrhie) { if(itrhb != itrhe) { itrhib = iterator_geometry_to_set<polygon_90_concept, typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(*itrhb, LOW, orient_, !is_hole_); itrhie = iterator_geometry_to_set<polygon_90_concept, typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(*itrhb, HIGH, orient_, !is_hole_); ++itrhb; } else { //this is the same case as above //itrhib = itrhie = iterator_geometry_to_set<polygon_90_concept, // typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(); } } } } else { ++itrb; if(itrb == itre) { if(itrhb != itrhe) { itrhib = iterator_geometry_to_set<polygon_90_concept, typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(*itrhb, LOW, orient_, !is_hole_); itrhie = iterator_geometry_to_set<polygon_90_concept, typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(*itrhb, HIGH, orient_, !is_hole_); ++itrhb; } } } return *this; } inline const iterator_geometry_to_set operator++(int) { iterator_geometry_to_set tmp(*this); ++(*this); return tmp; } inline bool operator==(const iterator_geometry_to_set& that) const { return itrb == that.itrb && itrhb == that.itrhb && itrhib == that.itrhib; } inline bool operator!=(const iterator_geometry_to_set& that) const { return !(*this == that); } inline reference operator*() const { if(itrb != itre) return *itrb; return *itrhib; } }; } } #endif detail/polygon_set_view.hpp 0000644 00000021357 15125572616 0012135 0 ustar 00 /* 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_SET_VIEW_HPP #define BOOST_POLYGON_POLYGON_SET_VIEW_HPP namespace boost { namespace polygon{ template <typename coordinate_type> inline void polygon_set_data<coordinate_type>::clean() const { if(dirty_) { //polygon_45_set_data<coordinate_type> tmp; //very important: //the 45 degree algorithm does not satisfy //the precondition of arbitrary polygon formation //that vertices be "linearly consistent" //therefore it doesn't work to fall back on 45-degree //booleans for arbitrary angle polygons //if(0) { //downcast(tmp) ) { // tmp.clean(); // data_.clear(); // is_45_ = true; // polygon_set_data<coordinate_type> tmp2; // tmp2.insert(tmp); // data_.swap(tmp2.data_); // dirty_ = false; // sort(); //} else { sort(); arbitrary_boolean_op<coordinate_type> abo; polygon_set_data<coordinate_type> tmp2; abo.execute(tmp2, begin(), end(), end(), end(), 0); data_.swap(tmp2.data_); is_45_ = tmp2.is_45_; dirty_ = false; //} } } template <> inline void polygon_set_data<double>::clean() const { if(dirty_) { sort(); arbitrary_boolean_op<double> abo; polygon_set_data<double> tmp2; abo.execute(tmp2, begin(), end(), end(), end(), 0); data_.swap(tmp2.data_); is_45_ = tmp2.is_45_; dirty_ = false; } } template <typename value_type, typename arg_type> inline void insert_into_view_arg(value_type& dest, const arg_type& arg); template <typename ltype, typename rtype, int op_type> class polygon_set_view; template <typename ltype, typename rtype, int op_type> struct polygon_set_traits<polygon_set_view<ltype, rtype, op_type> > { typedef typename polygon_set_view<ltype, rtype, op_type>::coordinate_type coordinate_type; typedef typename polygon_set_view<ltype, rtype, op_type>::iterator_type iterator_type; typedef typename polygon_set_view<ltype, rtype, op_type>::operator_arg_type operator_arg_type; static inline iterator_type begin(const polygon_set_view<ltype, rtype, op_type>& polygon_set); static inline iterator_type end(const polygon_set_view<ltype, rtype, op_type>& polygon_set); static inline bool clean(const polygon_set_view<ltype, rtype, op_type>& polygon_set); static inline bool sort(const polygon_set_view<ltype, rtype, op_type>& polygon_set); }; //template <typename value_type, typename geometry_type_1, typename geometry_type_2, int op_type> //void execute_boolean_op(value_type& output_, const geometry_type_1& lvalue_, const geometry_type_2& rvalue_, // double coord) { // typedef geometry_type_1 ltype; // typedef geometry_type_2 rtype; // typedef typename polygon_set_traits<ltype>::coordinate_type coordinate_type; // value_type linput_; // value_type rinput_; // insert_into_view_arg(linput_, lvalue_); // insert_into_view_arg(rinput_, rvalue_); // arbitrary_boolean_op<coordinate_type> abo; // abo.execute(output_, linput_.begin(), linput_.end(), // rinput_.begin(), rinput_.end(), op_type); //} template <typename value_type, typename geometry_type_1, typename geometry_type_2, int op_type> void execute_boolean_op(value_type& output_, const geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { typedef geometry_type_1 ltype; //typedef geometry_type_2 rtype; typedef typename polygon_set_traits<ltype>::coordinate_type coordinate_type; value_type linput_; value_type rinput_; insert_into_view_arg(linput_, lvalue_); insert_into_view_arg(rinput_, rvalue_); polygon_45_set_data<coordinate_type> l45, r45, o45; // if(linput_.downcast(l45) && rinput_.downcast(r45)) { // //the op codes are screwed up between 45 and arbitrary //#ifdef BOOST_POLYGON_MSVC //#pragma warning (push) //#pragma warning (disable: 4127) //#endif // if(op_type < 2) // l45.template applyAdaptiveBoolean_<op_type>(o45, r45); // else if(op_type == 2) // l45.template applyAdaptiveBoolean_<3>(o45, r45); // else // l45.template applyAdaptiveBoolean_<2>(o45, r45); //#ifdef BOOST_POLYGON_MSVC //#pragma warning (pop) //#endif // output_.insert(o45); // } else { arbitrary_boolean_op<coordinate_type> abo; abo.execute(output_, linput_.begin(), linput_.end(), rinput_.begin(), rinput_.end(), op_type); // } } template <typename ltype, typename rtype, int op_type> class polygon_set_view { public: typedef typename polygon_set_traits<ltype>::coordinate_type coordinate_type; typedef polygon_set_data<coordinate_type> value_type; typedef typename value_type::iterator_type iterator_type; typedef polygon_set_view operator_arg_type; private: const ltype& lvalue_; const rtype& rvalue_; mutable value_type output_; mutable bool evaluated_; polygon_set_view& operator=(const polygon_set_view&); public: polygon_set_view(const ltype& lvalue, const rtype& rvalue ) : lvalue_(lvalue), rvalue_(rvalue), output_(), evaluated_(false) {} // get iterator to begin vertex data public: const value_type& value() const { if(!evaluated_) { evaluated_ = true; execute_boolean_op<value_type, ltype, rtype, op_type>(output_, lvalue_, rvalue_); } return output_; } public: iterator_type begin() const { return value().begin(); } iterator_type end() const { return value().end(); } bool dirty() const { return false; } //result of a boolean is clean bool sorted() const { return true; } //result of a boolean is sorted void sort() const {} //is always sorted }; template <typename ltype, typename rtype, int op_type> typename polygon_set_traits<polygon_set_view<ltype, rtype, op_type> >::iterator_type polygon_set_traits<polygon_set_view<ltype, rtype, op_type> >:: begin(const polygon_set_view<ltype, rtype, op_type>& polygon_set) { return polygon_set.begin(); } template <typename ltype, typename rtype, int op_type> typename polygon_set_traits<polygon_set_view<ltype, rtype, op_type> >::iterator_type polygon_set_traits<polygon_set_view<ltype, rtype, op_type> >:: end(const polygon_set_view<ltype, rtype, op_type>& polygon_set) { return polygon_set.end(); } template <typename ltype, typename rtype, int op_type> bool polygon_set_traits<polygon_set_view<ltype, rtype, op_type> >:: clean(const polygon_set_view<ltype, rtype, op_type>& ) { return true; } template <typename ltype, typename rtype, int op_type> bool polygon_set_traits<polygon_set_view<ltype, rtype, op_type> >:: sort(const polygon_set_view<ltype, rtype, op_type>& ) { return true; } template <typename value_type, typename arg_type> inline void insert_into_view_arg(value_type& dest, const arg_type& arg) { typedef typename polygon_set_traits<arg_type>::iterator_type literator; literator itr1, itr2; itr1 = polygon_set_traits<arg_type>::begin(arg); itr2 = polygon_set_traits<arg_type>::end(arg); dest.insert(itr1, itr2); } template <typename geometry_type_1, typename geometry_type_2, int op_type> geometry_type_1& self_assignment_boolean_op(geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { typedef geometry_type_1 ltype; typedef typename polygon_set_traits<ltype>::coordinate_type coordinate_type; typedef polygon_set_data<coordinate_type> value_type; value_type output_; execute_boolean_op<value_type, geometry_type_1, geometry_type_2, op_type>(output_, lvalue_, rvalue_); polygon_set_mutable_traits<geometry_type_1>::set(lvalue_, output_.begin(), output_.end()); return lvalue_; } // copy constructor template <typename coordinate_type> template <typename ltype, typename rtype, int op_type> polygon_set_data<coordinate_type>::polygon_set_data(const polygon_set_view<ltype, rtype, op_type>& that) : data_(that.value().data_), dirty_(that.value().dirty_), unsorted_(that.value().unsorted_), is_45_(that.value().is_45_) {} // equivalence operator template <typename coordinate_type> inline bool polygon_set_data<coordinate_type>::operator==(const polygon_set_data<coordinate_type>& p) const { typedef polygon_set_data<coordinate_type> value_type; value_type output_; execute_boolean_op<value_type, value_type, value_type, 2>(output_, (*this), p); return output_.data_.empty(); } template <typename ltype, typename rtype, int op_type> struct geometry_concept<polygon_set_view<ltype, rtype, op_type> > { typedef polygon_set_concept type; }; } } #endif detail/polygon_arbitrary_formation.hpp 0000644 00000410156 15125572616 0014364 0 ustar 00 /* 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_ARBITRARY_FORMATION_HPP #define BOOST_POLYGON_POLYGON_ARBITRARY_FORMATION_HPP namespace boost { namespace polygon{ template <typename T, typename T2> struct PolyLineArbitraryByConcept {}; template <typename T> class poly_line_arbitrary_polygon_data; template <typename T> class poly_line_arbitrary_hole_data; template <typename Unit> struct scanline_base { typedef point_data<Unit> Point; typedef std::pair<Point, Point> half_edge; class less_point { public: typedef Point first_argument_type; typedef Point second_argument_type; typedef bool result_type; inline less_point() {} inline bool operator () (const Point& pt1, const Point& pt2) const { if(pt1.get(HORIZONTAL) < pt2.get(HORIZONTAL)) return true; if(pt1.get(HORIZONTAL) == pt2.get(HORIZONTAL)) { if(pt1.get(VERTICAL) < pt2.get(VERTICAL)) return true; } return false; } }; static inline bool between(Point pt, Point pt1, Point pt2) { less_point lp; if(lp(pt1, pt2)) return lp(pt, pt2) && lp(pt1, pt); return lp(pt, pt1) && lp(pt2, pt); } template <typename area_type> static inline Unit compute_intercept(const area_type& dy2, const area_type& dx1, const area_type& dx2) { //intercept = dy2 * dx1 / dx2 //return (Unit)(((area_type)dy2 * (area_type)dx1) / (area_type)dx2); area_type dx1_q = dx1 / dx2; area_type dx1_r = dx1 % dx2; return dx1_q * dy2 + (dy2 * dx1_r)/dx2; } template <typename area_type> static inline bool equal_slope(area_type dx1, area_type dy1, area_type dx2, area_type dy2) { typedef typename coordinate_traits<Unit>::unsigned_area_type unsigned_product_type; unsigned_product_type cross_1 = (unsigned_product_type)(dx2 < 0 ? -dx2 :dx2) * (unsigned_product_type)(dy1 < 0 ? -dy1 : dy1); unsigned_product_type cross_2 = (unsigned_product_type)(dx1 < 0 ? -dx1 :dx1) * (unsigned_product_type)(dy2 < 0 ? -dy2 : dy2); int dx1_sign = dx1 < 0 ? -1 : 1; int dx2_sign = dx2 < 0 ? -1 : 1; int dy1_sign = dy1 < 0 ? -1 : 1; int dy2_sign = dy2 < 0 ? -1 : 1; int cross_1_sign = dx2_sign * dy1_sign; int cross_2_sign = dx1_sign * dy2_sign; return cross_1 == cross_2 && (cross_1_sign == cross_2_sign || cross_1 == 0); } template <typename T> static inline bool equal_slope_hp(const T& dx1, const T& dy1, const T& dx2, const T& dy2) { return dx1 * dy2 == dx2 * dy1; } static inline bool equal_slope(const Unit& x, const Unit& y, const Point& pt1, const Point& pt2) { const Point* pts[2] = {&pt1, &pt2}; typedef typename coordinate_traits<Unit>::manhattan_area_type at; at dy2 = (at)pts[1]->get(VERTICAL) - (at)y; at dy1 = (at)pts[0]->get(VERTICAL) - (at)y; at dx2 = (at)pts[1]->get(HORIZONTAL) - (at)x; at dx1 = (at)pts[0]->get(HORIZONTAL) - (at)x; return equal_slope(dx1, dy1, dx2, dy2); } template <typename area_type> static inline bool less_slope(area_type dx1, area_type dy1, area_type dx2, area_type dy2) { //reflext x and y slopes to right hand side half plane if(dx1 < 0) { dy1 *= -1; dx1 *= -1; } else if(dx1 == 0) { //if the first slope is vertical the first cannot be less return false; } if(dx2 < 0) { dy2 *= -1; dx2 *= -1; } else if(dx2 == 0) { //if the second slope is vertical the first is always less unless it is also vertical, in which case they are equal return dx1 != 0; } typedef typename coordinate_traits<Unit>::unsigned_area_type unsigned_product_type; unsigned_product_type cross_1 = (unsigned_product_type)(dx2 < 0 ? -dx2 :dx2) * (unsigned_product_type)(dy1 < 0 ? -dy1 : dy1); unsigned_product_type cross_2 = (unsigned_product_type)(dx1 < 0 ? -dx1 :dx1) * (unsigned_product_type)(dy2 < 0 ? -dy2 : dy2); int dx1_sign = dx1 < 0 ? -1 : 1; int dx2_sign = dx2 < 0 ? -1 : 1; int dy1_sign = dy1 < 0 ? -1 : 1; int dy2_sign = dy2 < 0 ? -1 : 1; int cross_1_sign = dx2_sign * dy1_sign; int cross_2_sign = dx1_sign * dy2_sign; if(cross_1_sign < cross_2_sign) return true; if(cross_2_sign < cross_1_sign) return false; if(cross_1_sign == -1) return cross_2 < cross_1; return cross_1 < cross_2; } static inline bool less_slope(const Unit& x, const Unit& y, const Point& pt1, const Point& pt2) { const Point* pts[2] = {&pt1, &pt2}; //compute y value on edge from pt_ to pts[1] at the x value of pts[0] typedef typename coordinate_traits<Unit>::manhattan_area_type at; at dy2 = (at)pts[1]->get(VERTICAL) - (at)y; at dy1 = (at)pts[0]->get(VERTICAL) - (at)y; at dx2 = (at)pts[1]->get(HORIZONTAL) - (at)x; at dx1 = (at)pts[0]->get(HORIZONTAL) - (at)x; return less_slope(dx1, dy1, dx2, dy2); } //return -1 below, 0 on and 1 above line static inline int on_above_or_below(Point pt, const half_edge& he) { if(pt == he.first || pt == he.second) return 0; if(equal_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), he.first, he.second)) return 0; bool less_result = less_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), he.first, he.second); int retval = less_result ? -1 : 1; less_point lp; if(lp(he.second, he.first)) retval *= -1; if(!between(pt, he.first, he.second)) retval *= -1; return retval; } //returns true is the segment intersects the integer grid square with lower //left corner at point static inline bool intersects_grid(Point pt, const half_edge& he) { if(pt == he.second) return true; if(pt == he.first) return true; rectangle_data<Unit> rect1; set_points(rect1, he.first, he.second); if(contains(rect1, pt, true)) { if(is_vertical(he) || is_horizontal(he)) return true; } else { return false; //can't intersect a grid not within bounding box } Unit x = pt.get(HORIZONTAL); Unit y = pt.get(VERTICAL); if(equal_slope(x, y, he.first, he.second) && between(pt, he.first, he.second)) return true; Point pt01(pt.get(HORIZONTAL), pt.get(VERTICAL) + 1); Point pt10(pt.get(HORIZONTAL) + 1, pt.get(VERTICAL)); Point pt11(pt.get(HORIZONTAL) + 1, pt.get(VERTICAL) + 1); // if(pt01 == he.first) return true; // if(pt10 == he.first) return true; // if(pt11 == he.first) return true; // if(pt01 == he.second) return true; // if(pt10 == he.second) return true; // if(pt11 == he.second) return true; //check non-integer intersections half_edge widget1(pt, pt11); //intersects but not just at pt11 if(intersects(widget1, he) && on_above_or_below(pt11, he)) return true; half_edge widget2(pt01, pt10); //intersects but not just at pt01 or 10 if(intersects(widget2, he) && on_above_or_below(pt01, he) && on_above_or_below(pt10, he)) return true; return false; } static inline Unit evalAtXforYlazy(Unit xIn, Point pt, Point other_pt) { long double evalAtXforYret, evalAtXforYxIn, evalAtXforYx1, evalAtXforYy1, evalAtXforYdx1, evalAtXforYdx, evalAtXforYdy, evalAtXforYx2, evalAtXforYy2, evalAtXforY0; //y = (x - x1)dy/dx + y1 //y = (xIn - pt.x)*(other_pt.y-pt.y)/(other_pt.x-pt.x) + pt.y //assert pt.x != other_pt.x if(pt.y() == other_pt.y()) return pt.y(); evalAtXforYxIn = xIn; evalAtXforYx1 = pt.get(HORIZONTAL); evalAtXforYy1 = pt.get(VERTICAL); evalAtXforYdx1 = evalAtXforYxIn - evalAtXforYx1; evalAtXforY0 = 0; if(evalAtXforYdx1 == evalAtXforY0) return (Unit)evalAtXforYy1; evalAtXforYx2 = other_pt.get(HORIZONTAL); evalAtXforYy2 = other_pt.get(VERTICAL); evalAtXforYdx = evalAtXforYx2 - evalAtXforYx1; evalAtXforYdy = evalAtXforYy2 - evalAtXforYy1; evalAtXforYret = ((evalAtXforYdx1) * evalAtXforYdy / evalAtXforYdx + evalAtXforYy1); return (Unit)evalAtXforYret; } static inline typename high_precision_type<Unit>::type evalAtXforY(Unit xIn, Point pt, Point other_pt) { typename high_precision_type<Unit>::type evalAtXforYret, evalAtXforYxIn, evalAtXforYx1, evalAtXforYy1, evalAtXforYdx1, evalAtXforYdx, evalAtXforYdy, evalAtXforYx2, evalAtXforYy2, evalAtXforY0; //y = (x - x1)dy/dx + y1 //y = (xIn - pt.x)*(other_pt.y-pt.y)/(other_pt.x-pt.x) + pt.y //assert pt.x != other_pt.x typedef typename high_precision_type<Unit>::type high_precision; if(pt.y() == other_pt.y()) return (high_precision)pt.y(); evalAtXforYxIn = (high_precision)xIn; evalAtXforYx1 = pt.get(HORIZONTAL); evalAtXforYy1 = pt.get(VERTICAL); evalAtXforYdx1 = evalAtXforYxIn - evalAtXforYx1; evalAtXforY0 = high_precision(0); if(evalAtXforYdx1 == evalAtXforY0) return evalAtXforYret = evalAtXforYy1; evalAtXforYx2 = (high_precision)other_pt.get(HORIZONTAL); evalAtXforYy2 = (high_precision)other_pt.get(VERTICAL); evalAtXforYdx = evalAtXforYx2 - evalAtXforYx1; evalAtXforYdy = evalAtXforYy2 - evalAtXforYy1; evalAtXforYret = ((evalAtXforYdx1) * evalAtXforYdy / evalAtXforYdx + evalAtXforYy1); return evalAtXforYret; } struct evalAtXforYPack { typename high_precision_type<Unit>::type evalAtXforYret, evalAtXforYxIn, evalAtXforYx1, evalAtXforYy1, evalAtXforYdx1, evalAtXforYdx, evalAtXforYdy, evalAtXforYx2, evalAtXforYy2, evalAtXforY0; inline const typename high_precision_type<Unit>::type& evalAtXforY(Unit xIn, Point pt, Point other_pt) { //y = (x - x1)dy/dx + y1 //y = (xIn - pt.x)*(other_pt.y-pt.y)/(other_pt.x-pt.x) + pt.y //assert pt.x != other_pt.x typedef typename high_precision_type<Unit>::type high_precision; if(pt.y() == other_pt.y()) { evalAtXforYret = (high_precision)pt.y(); return evalAtXforYret; } evalAtXforYxIn = (high_precision)xIn; evalAtXforYx1 = pt.get(HORIZONTAL); evalAtXforYy1 = pt.get(VERTICAL); evalAtXforYdx1 = evalAtXforYxIn - evalAtXforYx1; evalAtXforY0 = high_precision(0); if(evalAtXforYdx1 == evalAtXforY0) return evalAtXforYret = evalAtXforYy1; evalAtXforYx2 = (high_precision)other_pt.get(HORIZONTAL); evalAtXforYy2 = (high_precision)other_pt.get(VERTICAL); evalAtXforYdx = evalAtXforYx2 - evalAtXforYx1; evalAtXforYdy = evalAtXforYy2 - evalAtXforYy1; evalAtXforYret = ((evalAtXforYdx1) * evalAtXforYdy / evalAtXforYdx + evalAtXforYy1); return evalAtXforYret; } }; static inline bool is_vertical(const half_edge& he) { return he.first.get(HORIZONTAL) == he.second.get(HORIZONTAL); } static inline bool is_horizontal(const half_edge& he) { return he.first.get(VERTICAL) == he.second.get(VERTICAL); } static inline bool is_45_degree(const half_edge& he) { return euclidean_distance(he.first, he.second, HORIZONTAL) == euclidean_distance(he.first, he.second, VERTICAL); } //scanline comparator functor class less_half_edge { private: Unit *x_; //x value at which to apply comparison int *justBefore_; evalAtXforYPack * pack_; public: typedef half_edge first_argument_type; typedef half_edge second_argument_type; typedef bool result_type; inline less_half_edge() : x_(0), justBefore_(0), pack_(0) {} inline less_half_edge(Unit *x, int *justBefore, evalAtXforYPack * packIn) : x_(x), justBefore_(justBefore), pack_(packIn) {} inline less_half_edge(const less_half_edge& that) : x_(that.x_), justBefore_(that.justBefore_), pack_(that.pack_){} inline less_half_edge& operator=(const less_half_edge& that) { x_ = that.x_; justBefore_ = that.justBefore_; pack_ = that.pack_; return *this; } inline bool operator () (const half_edge& elm1, const half_edge& elm2) const { if((std::max)(elm1.first.y(), elm1.second.y()) < (std::min)(elm2.first.y(), elm2.second.y())) return true; if((std::min)(elm1.first.y(), elm1.second.y()) > (std::max)(elm2.first.y(), elm2.second.y())) return false; //check if either x of elem1 is equal to x_ Unit localx = *x_; Unit elm1y = 0; bool elm1_at_x = false; if(localx == elm1.first.get(HORIZONTAL)) { elm1_at_x = true; elm1y = elm1.first.get(VERTICAL); } else if(localx == elm1.second.get(HORIZONTAL)) { elm1_at_x = true; elm1y = elm1.second.get(VERTICAL); } Unit elm2y = 0; bool elm2_at_x = false; if(localx == elm2.first.get(HORIZONTAL)) { elm2_at_x = true; elm2y = elm2.first.get(VERTICAL); } else if(localx == elm2.second.get(HORIZONTAL)) { elm2_at_x = true; elm2y = elm2.second.get(VERTICAL); } bool retval = false; if(!(elm1_at_x && elm2_at_x)) { //at least one of the segments doesn't have an end point a the current x //-1 below, 1 above int pt1_oab = on_above_or_below(elm1.first, half_edge(elm2.first, elm2.second)); int pt2_oab = on_above_or_below(elm1.second, half_edge(elm2.first, elm2.second)); if(pt1_oab == pt2_oab) { if(pt1_oab == -1) retval = true; //pt1 is below elm2 so elm1 is below elm2 } else { //the segments can't cross so elm2 is on whatever side of elm1 that one of its ends is int pt3_oab = on_above_or_below(elm2.first, half_edge(elm1.first, elm1.second)); if(pt3_oab == 1) retval = true; //elm1's point is above elm1 } } else { if(elm1y < elm2y) { retval = true; } else if(elm1y == elm2y) { if(elm1 == elm2) return false; retval = less_slope(elm1.second.get(HORIZONTAL) - elm1.first.get(HORIZONTAL), elm1.second.get(VERTICAL) - elm1.first.get(VERTICAL), elm2.second.get(HORIZONTAL) - elm2.first.get(HORIZONTAL), elm2.second.get(VERTICAL) - elm2.first.get(VERTICAL)); retval = ((*justBefore_) != 0) ^ retval; } } return retval; } }; template <typename unsigned_product_type> static inline void unsigned_add(unsigned_product_type& result, int& result_sign, unsigned_product_type a, int a_sign, unsigned_product_type b, int b_sign) { int switcher = 0; if(a_sign < 0) switcher += 1; if(b_sign < 0) switcher += 2; if(a < b) switcher += 4; switch (switcher) { case 0: //both positive result = a + b; result_sign = 1; break; case 1: //a is negative result = a - b; result_sign = -1; break; case 2: //b is negative result = a - b; result_sign = 1; break; case 3: //both negative result = a + b; result_sign = -1; break; case 4: //both positive result = a + b; result_sign = 1; break; case 5: //a is negative result = b - a; result_sign = 1; break; case 6: //b is negative result = b - a; result_sign = -1; break; case 7: //both negative result = b + a; result_sign = -1; break; }; } struct compute_intersection_pack { typedef typename high_precision_type<Unit>::type high_precision; high_precision y_high, dx1, dy1, dx2, dy2, x11, x21, y11, y21, x_num, y_num, x_den, y_den, x, y; static inline bool compute_lazy_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, bool projected = false, bool round_closest = false) { long double y_high, dx1, dy1, dx2, dy2, x11, x21, y11, y21, x_num, y_num, x_den, y_den, x, y; typedef rectangle_data<Unit> Rectangle; Rectangle rect1, rect2; set_points(rect1, he1.first, he1.second); set_points(rect2, he2.first, he2.second); if(!projected && !::boost::polygon::intersects(rect1, rect2, true)) return false; if(is_vertical(he1)) { if(is_vertical(he2)) return false; y_high = evalAtXforYlazy(he1.first.get(HORIZONTAL), he2.first, he2.second); Unit y_local = (Unit)y_high; if(y_high < y_local) --y_local; if(projected || contains(rect1.get(VERTICAL), y_local, true)) { intersection = Point(he1.first.get(HORIZONTAL), y_local); return true; } else { return false; } } else if(is_vertical(he2)) { y_high = evalAtXforYlazy(he2.first.get(HORIZONTAL), he1.first, he1.second); Unit y_local = (Unit)y_high; if(y_high < y_local) --y_local; if(projected || contains(rect2.get(VERTICAL), y_local, true)) { intersection = Point(he2.first.get(HORIZONTAL), y_local); return true; } else { return false; } } //the bounding boxes of the two line segments intersect, so we check closer to find the intersection point dy2 = (he2.second.get(VERTICAL)) - (he2.first.get(VERTICAL)); dy1 = (he1.second.get(VERTICAL)) - (he1.first.get(VERTICAL)); dx2 = (he2.second.get(HORIZONTAL)) - (he2.first.get(HORIZONTAL)); dx1 = (he1.second.get(HORIZONTAL)) - (he1.first.get(HORIZONTAL)); if(equal_slope_hp(dx1, dy1, dx2, dy2)) return false; //the line segments have different slopes //we can assume that the line segments are not vertical because such an intersection is handled elsewhere x11 = (he1.first.get(HORIZONTAL)); x21 = (he2.first.get(HORIZONTAL)); y11 = (he1.first.get(VERTICAL)); y21 = (he2.first.get(VERTICAL)); //Unit exp_x = ((at)x11 * (at)dy1 * (at)dx2 - (at)x21 * (at)dy2 * (at)dx1 + (at)y21 * (at)dx1 * (at)dx2 - (at)y11 * (at)dx1 * (at)dx2) / ((at)dy1 * (at)dx2 - (at)dy2 * (at)dx1); //Unit exp_y = ((at)y11 * (at)dx1 * (at)dy2 - (at)y21 * (at)dx2 * (at)dy1 + (at)x21 * (at)dy1 * (at)dy2 - (at)x11 * (at)dy1 * (at)dy2) / ((at)dx1 * (at)dy2 - (at)dx2 * (at)dy1); x_num = (x11 * dy1 * dx2 - x21 * dy2 * dx1 + y21 * dx1 * dx2 - y11 * dx1 * dx2); x_den = (dy1 * dx2 - dy2 * dx1); y_num = (y11 * dx1 * dy2 - y21 * dx2 * dy1 + x21 * dy1 * dy2 - x11 * dy1 * dy2); y_den = (dx1 * dy2 - dx2 * dy1); x = x_num / x_den; y = y_num / y_den; //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << "\n"; //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << "\n"; //Unit exp_x = compute_x_intercept<at>(x11, x21, y11, y21, dy1, dy2, dx1, dx2); //Unit exp_y = compute_x_intercept<at>(y11, y21, x11, x21, dx1, dx2, dy1, dy2); if(round_closest) { x = x + 0.5; y = y + 0.5; } Unit x_unit = (Unit)(x); Unit y_unit = (Unit)(y); //truncate downward if it went up due to negative number if(x < x_unit) --x_unit; if(y < y_unit) --y_unit; if(is_horizontal(he1)) y_unit = he1.first.y(); if(is_horizontal(he2)) y_unit = he2.first.y(); //if(x != exp_x || y != exp_y) // std::cout << exp_x << " " << exp_y << " " << x << " " << y << "\n"; //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); //Unit y2 = evalAtXforY(exp_x, he2.first, he2.second); //std::cout << exp_x << " " << exp_y << " " << y1 << " " << y2 << "\n"; Point result(x_unit, y_unit); if(!projected && !contains(rect1, result, true)) return false; if(!projected && !contains(rect2, result, true)) return false; if(projected) { rectangle_data<long double> inf_rect(-(long double)(std::numeric_limits<Unit>::max)(), -(long double) (std::numeric_limits<Unit>::max)(), (long double)(std::numeric_limits<Unit>::max)(), (long double) (std::numeric_limits<Unit>::max)() ); if(contains(inf_rect, point_data<long double>(x, y), true)) { intersection = result; return true; } else return false; } intersection = result; return true; } inline bool compute_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, bool projected = false, bool round_closest = false) { if(!projected && !intersects(he1, he2)) return false; bool lazy_success = compute_lazy_intersection(intersection, he1, he2, projected); if(!projected) { if(lazy_success) { if(intersects_grid(intersection, he1) && intersects_grid(intersection, he2)) return true; } } else { return lazy_success; } return compute_exact_intersection(intersection, he1, he2, projected, round_closest); } inline bool compute_exact_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, bool projected = false, bool round_closest = false) { if(!projected && !intersects(he1, he2)) return false; typedef rectangle_data<Unit> Rectangle; Rectangle rect1, rect2; set_points(rect1, he1.first, he1.second); set_points(rect2, he2.first, he2.second); if(!::boost::polygon::intersects(rect1, rect2, true)) return false; if(is_vertical(he1)) { if(is_vertical(he2)) return false; y_high = evalAtXforY(he1.first.get(HORIZONTAL), he2.first, he2.second); Unit y = convert_high_precision_type<Unit>(y_high); if(y_high < (high_precision)y) --y; if(contains(rect1.get(VERTICAL), y, true)) { intersection = Point(he1.first.get(HORIZONTAL), y); return true; } else { return false; } } else if(is_vertical(he2)) { y_high = evalAtXforY(he2.first.get(HORIZONTAL), he1.first, he1.second); Unit y = convert_high_precision_type<Unit>(y_high); if(y_high < (high_precision)y) --y; if(contains(rect2.get(VERTICAL), y, true)) { intersection = Point(he2.first.get(HORIZONTAL), y); return true; } else { return false; } } //the bounding boxes of the two line segments intersect, so we check closer to find the intersection point dy2 = (high_precision)(he2.second.get(VERTICAL)) - (high_precision)(he2.first.get(VERTICAL)); dy1 = (high_precision)(he1.second.get(VERTICAL)) - (high_precision)(he1.first.get(VERTICAL)); dx2 = (high_precision)(he2.second.get(HORIZONTAL)) - (high_precision)(he2.first.get(HORIZONTAL)); dx1 = (high_precision)(he1.second.get(HORIZONTAL)) - (high_precision)(he1.first.get(HORIZONTAL)); if(equal_slope_hp(dx1, dy1, dx2, dy2)) return false; //the line segments have different slopes //we can assume that the line segments are not vertical because such an intersection is handled elsewhere x11 = (high_precision)(he1.first.get(HORIZONTAL)); x21 = (high_precision)(he2.first.get(HORIZONTAL)); y11 = (high_precision)(he1.first.get(VERTICAL)); y21 = (high_precision)(he2.first.get(VERTICAL)); //Unit exp_x = ((at)x11 * (at)dy1 * (at)dx2 - (at)x21 * (at)dy2 * (at)dx1 + (at)y21 * (at)dx1 * (at)dx2 - (at)y11 * (at)dx1 * (at)dx2) / ((at)dy1 * (at)dx2 - (at)dy2 * (at)dx1); //Unit exp_y = ((at)y11 * (at)dx1 * (at)dy2 - (at)y21 * (at)dx2 * (at)dy1 + (at)x21 * (at)dy1 * (at)dy2 - (at)x11 * (at)dy1 * (at)dy2) / ((at)dx1 * (at)dy2 - (at)dx2 * (at)dy1); x_num = (x11 * dy1 * dx2 - x21 * dy2 * dx1 + y21 * dx1 * dx2 - y11 * dx1 * dx2); x_den = (dy1 * dx2 - dy2 * dx1); y_num = (y11 * dx1 * dy2 - y21 * dx2 * dy1 + x21 * dy1 * dy2 - x11 * dy1 * dy2); y_den = (dx1 * dy2 - dx2 * dy1); x = x_num / x_den; y = y_num / y_den; //std::cout << x << " " << y << "\n"; //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << "\n"; //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << "\n"; //Unit exp_x = compute_x_intercept<at>(x11, x21, y11, y21, dy1, dy2, dx1, dx2); //Unit exp_y = compute_x_intercept<at>(y11, y21, x11, x21, dx1, dx2, dy1, dy2); if(round_closest) { x = x + (high_precision)0.5; y = y + (high_precision)0.5; } Unit x_unit = convert_high_precision_type<Unit>(x); Unit y_unit = convert_high_precision_type<Unit>(y); //truncate downward if it went up due to negative number if(x < (high_precision)x_unit) --x_unit; if(y < (high_precision)y_unit) --y_unit; if(is_horizontal(he1)) y_unit = he1.first.y(); if(is_horizontal(he2)) y_unit = he2.first.y(); //if(x != exp_x || y != exp_y) // std::cout << exp_x << " " << exp_y << " " << x << " " << y << "\n"; //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); //Unit y2 = evalAtXforY(exp_x, he2.first, he2.second); //std::cout << exp_x << " " << exp_y << " " << y1 << " " << y2 << "\n"; Point result(x_unit, y_unit); if(!contains(rect1, result, true)) return false; if(!contains(rect2, result, true)) return false; if(projected) { high_precision b1 = (high_precision) (std::numeric_limits<Unit>::min)(); high_precision b2 = (high_precision) (std::numeric_limits<Unit>::max)(); if(x > b2 || y > b2 || x < b1 || y < b1) return false; } intersection = result; return true; } }; static inline bool compute_intersection(Point& intersection, const half_edge& he1, const half_edge& he2) { typedef typename high_precision_type<Unit>::type high_precision; typedef rectangle_data<Unit> Rectangle; Rectangle rect1, rect2; set_points(rect1, he1.first, he1.second); set_points(rect2, he2.first, he2.second); if(!::boost::polygon::intersects(rect1, rect2, true)) return false; if(is_vertical(he1)) { if(is_vertical(he2)) return false; high_precision y_high = evalAtXforY(he1.first.get(HORIZONTAL), he2.first, he2.second); Unit y = convert_high_precision_type<Unit>(y_high); if(y_high < (high_precision)y) --y; if(contains(rect1.get(VERTICAL), y, true)) { intersection = Point(he1.first.get(HORIZONTAL), y); return true; } else { return false; } } else if(is_vertical(he2)) { high_precision y_high = evalAtXforY(he2.first.get(HORIZONTAL), he1.first, he1.second); Unit y = convert_high_precision_type<Unit>(y_high); if(y_high < (high_precision)y) --y; if(contains(rect2.get(VERTICAL), y, true)) { intersection = Point(he2.first.get(HORIZONTAL), y); return true; } else { return false; } } //the bounding boxes of the two line segments intersect, so we check closer to find the intersection point high_precision dy2 = (high_precision)(he2.second.get(VERTICAL)) - (high_precision)(he2.first.get(VERTICAL)); high_precision dy1 = (high_precision)(he1.second.get(VERTICAL)) - (high_precision)(he1.first.get(VERTICAL)); high_precision dx2 = (high_precision)(he2.second.get(HORIZONTAL)) - (high_precision)(he2.first.get(HORIZONTAL)); high_precision dx1 = (high_precision)(he1.second.get(HORIZONTAL)) - (high_precision)(he1.first.get(HORIZONTAL)); if(equal_slope_hp(dx1, dy1, dx2, dy2)) return false; //the line segments have different slopes //we can assume that the line segments are not vertical because such an intersection is handled elsewhere high_precision x11 = (high_precision)(he1.first.get(HORIZONTAL)); high_precision x21 = (high_precision)(he2.first.get(HORIZONTAL)); high_precision y11 = (high_precision)(he1.first.get(VERTICAL)); high_precision y21 = (high_precision)(he2.first.get(VERTICAL)); //Unit exp_x = ((at)x11 * (at)dy1 * (at)dx2 - (at)x21 * (at)dy2 * (at)dx1 + (at)y21 * (at)dx1 * (at)dx2 - (at)y11 * (at)dx1 * (at)dx2) / ((at)dy1 * (at)dx2 - (at)dy2 * (at)dx1); //Unit exp_y = ((at)y11 * (at)dx1 * (at)dy2 - (at)y21 * (at)dx2 * (at)dy1 + (at)x21 * (at)dy1 * (at)dy2 - (at)x11 * (at)dy1 * (at)dy2) / ((at)dx1 * (at)dy2 - (at)dx2 * (at)dy1); high_precision x_num = (x11 * dy1 * dx2 - x21 * dy2 * dx1 + y21 * dx1 * dx2 - y11 * dx1 * dx2); high_precision x_den = (dy1 * dx2 - dy2 * dx1); high_precision y_num = (y11 * dx1 * dy2 - y21 * dx2 * dy1 + x21 * dy1 * dy2 - x11 * dy1 * dy2); high_precision y_den = (dx1 * dy2 - dx2 * dy1); high_precision x = x_num / x_den; high_precision y = y_num / y_den; //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << "\n"; //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << "\n"; //Unit exp_x = compute_x_intercept<at>(x11, x21, y11, y21, dy1, dy2, dx1, dx2); //Unit exp_y = compute_x_intercept<at>(y11, y21, x11, x21, dx1, dx2, dy1, dy2); Unit x_unit = convert_high_precision_type<Unit>(x); Unit y_unit = convert_high_precision_type<Unit>(y); //truncate downward if it went up due to negative number if(x < (high_precision)x_unit) --x_unit; if(y < (high_precision)y_unit) --y_unit; if(is_horizontal(he1)) y_unit = he1.first.y(); if(is_horizontal(he2)) y_unit = he2.first.y(); //if(x != exp_x || y != exp_y) // std::cout << exp_x << " " << exp_y << " " << x << " " << y << "\n"; //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); //Unit y2 = evalAtXforY(exp_x, he2.first, he2.second); //std::cout << exp_x << " " << exp_y << " " << y1 << " " << y2 << "\n"; Point result(x_unit, y_unit); if(!contains(rect1, result, true)) return false; if(!contains(rect2, result, true)) return false; intersection = result; return true; } static inline bool intersects(const half_edge& he1, const half_edge& he2) { typedef rectangle_data<Unit> Rectangle; Rectangle rect1, rect2; set_points(rect1, he1.first, he1.second); set_points(rect2, he2.first, he2.second); if(::boost::polygon::intersects(rect1, rect2, false)) { if(he1.first == he2.first) { if(he1.second != he2.second && equal_slope(he1.first.get(HORIZONTAL), he1.first.get(VERTICAL), he1.second, he2.second)) { return true; } else { return false; } } if(he1.first == he2.second) { if(he1.second != he2.first && equal_slope(he1.first.get(HORIZONTAL), he1.first.get(VERTICAL), he1.second, he2.first)) { return true; } else { return false; } } if(he1.second == he2.first) { if(he1.first != he2.second && equal_slope(he1.second.get(HORIZONTAL), he1.second.get(VERTICAL), he1.first, he2.second)) { return true; } else { return false; } } if(he1.second == he2.second) { if(he1.first != he2.first && equal_slope(he1.second.get(HORIZONTAL), he1.second.get(VERTICAL), he1.first, he2.first)) { return true; } else { return false; } } int oab1 = on_above_or_below(he1.first, he2); if(oab1 == 0 && between(he1.first, he2.first, he2.second)) return true; int oab2 = on_above_or_below(he1.second, he2); if(oab2 == 0 && between(he1.second, he2.first, he2.second)) return true; if(oab1 == oab2 && oab1 != 0) return false; //both points of he1 are on same side of he2 int oab3 = on_above_or_below(he2.first, he1); if(oab3 == 0 && between(he2.first, he1.first, he1.second)) return true; int oab4 = on_above_or_below(he2.second, he1); if(oab4 == 0 && between(he2.second, he1.first, he1.second)) return true; if(oab3 == oab4) return false; //both points of he2 are on same side of he1 return true; //they must cross } if(is_vertical(he1) && is_vertical(he2) && he1.first.get(HORIZONTAL) == he2.first.get(HORIZONTAL)) return ::boost::polygon::intersects(rect1.get(VERTICAL), rect2.get(VERTICAL), false) && rect1.get(VERTICAL) != rect2.get(VERTICAL); if(is_horizontal(he1) && is_horizontal(he2) && he1.first.get(VERTICAL) == he2.first.get(VERTICAL)) return ::boost::polygon::intersects(rect1.get(HORIZONTAL), rect2.get(HORIZONTAL), false) && rect1.get(HORIZONTAL) != rect2.get(HORIZONTAL); return false; } class vertex_half_edge { public: typedef typename high_precision_type<Unit>::type high_precision; Point pt; Point other_pt; // 1, 0 or -1 int count; //dxdydTheta inline vertex_half_edge() : pt(), other_pt(), count() {} inline vertex_half_edge(const Point& point, const Point& other_point, int countIn) : pt(point), other_pt(other_point), count(countIn) {} inline vertex_half_edge(const vertex_half_edge& vertex) : pt(vertex.pt), other_pt(vertex.other_pt), count(vertex.count) {} inline vertex_half_edge& operator=(const vertex_half_edge& vertex){ pt = vertex.pt; other_pt = vertex.other_pt; count = vertex.count; return *this; } inline bool operator==(const vertex_half_edge& vertex) const { return pt == vertex.pt && other_pt == vertex.other_pt && count == vertex.count; } inline bool operator!=(const vertex_half_edge& vertex) const { return !((*this) == vertex); } inline bool operator<(const vertex_half_edge& vertex) const { if(pt.get(HORIZONTAL) < vertex.pt.get(HORIZONTAL)) return true; if(pt.get(HORIZONTAL) == vertex.pt.get(HORIZONTAL)) { if(pt.get(VERTICAL) < vertex.pt.get(VERTICAL)) return true; if(pt.get(VERTICAL) == vertex.pt.get(VERTICAL)) { return less_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), other_pt, vertex.other_pt); } } return false; } inline bool operator>(const vertex_half_edge& vertex) const { return vertex < (*this); } inline bool operator<=(const vertex_half_edge& vertex) const { return !((*this) > vertex); } inline bool operator>=(const vertex_half_edge& vertex) const { return !((*this) < vertex); } inline high_precision evalAtX(Unit xIn) const { return evalAtXforYlazy(xIn, pt, other_pt); } inline bool is_vertical() const { return pt.get(HORIZONTAL) == other_pt.get(HORIZONTAL); } inline bool is_begin() const { return pt.get(HORIZONTAL) < other_pt.get(HORIZONTAL) || (pt.get(HORIZONTAL) == other_pt.get(HORIZONTAL) && (pt.get(VERTICAL) < other_pt.get(VERTICAL))); } }; //when scanning Vertex45 for polygon formation we need a scanline comparator functor class less_vertex_half_edge { private: Unit *x_; //x value at which to apply comparison int *justBefore_; public: typedef vertex_half_edge first_argument_type; typedef vertex_half_edge second_argument_type; typedef bool result_type; inline less_vertex_half_edge() : x_(0), justBefore_(0) {} inline less_vertex_half_edge(Unit *x, int *justBefore) : x_(x), justBefore_(justBefore) {} inline less_vertex_half_edge(const less_vertex_half_edge& that) : x_(that.x_), justBefore_(that.justBefore_) {} inline less_vertex_half_edge& operator=(const less_vertex_half_edge& that) { x_ = that.x_; justBefore_ = that.justBefore_; return *this; } inline bool operator () (const vertex_half_edge& elm1, const vertex_half_edge& elm2) const { if((std::max)(elm1.pt.y(), elm1.other_pt.y()) < (std::min)(elm2.pt.y(), elm2.other_pt.y())) return true; if((std::min)(elm1.pt.y(), elm1.other_pt.y()) > (std::max)(elm2.pt.y(), elm2.other_pt.y())) return false; //check if either x of elem1 is equal to x_ Unit localx = *x_; Unit elm1y = 0; bool elm1_at_x = false; if(localx == elm1.pt.get(HORIZONTAL)) { elm1_at_x = true; elm1y = elm1.pt.get(VERTICAL); } else if(localx == elm1.other_pt.get(HORIZONTAL)) { elm1_at_x = true; elm1y = elm1.other_pt.get(VERTICAL); } Unit elm2y = 0; bool elm2_at_x = false; if(localx == elm2.pt.get(HORIZONTAL)) { elm2_at_x = true; elm2y = elm2.pt.get(VERTICAL); } else if(localx == elm2.other_pt.get(HORIZONTAL)) { elm2_at_x = true; elm2y = elm2.other_pt.get(VERTICAL); } bool retval = false; if(!(elm1_at_x && elm2_at_x)) { //at least one of the segments doesn't have an end point a the current x //-1 below, 1 above int pt1_oab = on_above_or_below(elm1.pt, half_edge(elm2.pt, elm2.other_pt)); int pt2_oab = on_above_or_below(elm1.other_pt, half_edge(elm2.pt, elm2.other_pt)); if(pt1_oab == pt2_oab) { if(pt1_oab == -1) retval = true; //pt1 is below elm2 so elm1 is below elm2 } else { //the segments can't cross so elm2 is on whatever side of elm1 that one of its ends is int pt3_oab = on_above_or_below(elm2.pt, half_edge(elm1.pt, elm1.other_pt)); if(pt3_oab == 1) retval = true; //elm1's point is above elm1 } } else { if(elm1y < elm2y) { retval = true; } else if(elm1y == elm2y) { if(elm1.pt == elm2.pt && elm1.other_pt == elm2.other_pt) return false; retval = less_slope(elm1.other_pt.get(HORIZONTAL) - elm1.pt.get(HORIZONTAL), elm1.other_pt.get(VERTICAL) - elm1.pt.get(VERTICAL), elm2.other_pt.get(HORIZONTAL) - elm2.pt.get(HORIZONTAL), elm2.other_pt.get(VERTICAL) - elm2.pt.get(VERTICAL)); retval = ((*justBefore_) != 0) ^ retval; } } return retval; } }; }; template <typename Unit> class polygon_arbitrary_formation : public scanline_base<Unit> { public: typedef typename scanline_base<Unit>::Point Point; typedef typename scanline_base<Unit>::half_edge half_edge; typedef typename scanline_base<Unit>::vertex_half_edge vertex_half_edge; typedef typename scanline_base<Unit>::less_vertex_half_edge less_vertex_half_edge; class poly_line_arbitrary { public: typedef typename std::list<Point>::const_iterator iterator; // default constructor of point does not initialize x and y inline poly_line_arbitrary() : points() {} //do nothing default constructor // initialize a polygon from x,y values, it is assumed that the first is an x // and that the input is a well behaved polygon template<class iT> inline poly_line_arbitrary& set(iT inputBegin, iT inputEnd) { points.clear(); //just in case there was some old data there while(inputBegin != inputEnd) { points.insert(points.end(), *inputBegin); ++inputBegin; } return *this; } // copy constructor (since we have dynamic memory) inline poly_line_arbitrary(const poly_line_arbitrary& that) : points(that.points) {} // assignment operator (since we have dynamic memory do a deep copy) inline poly_line_arbitrary& operator=(const poly_line_arbitrary& that) { points = that.points; return *this; } // get begin iterator, returns a pointer to a const Unit inline iterator begin() const { return points.begin(); } // get end iterator, returns a pointer to a const Unit inline iterator end() const { return points.end(); } inline std::size_t size() const { return points.size(); } //public data member std::list<Point> points; }; class active_tail_arbitrary { protected: //data poly_line_arbitrary* tailp_; active_tail_arbitrary *otherTailp_; std::list<active_tail_arbitrary*> holesList_; bool head_; public: /** * @brief iterator over coordinates of the figure */ typedef typename poly_line_arbitrary::iterator iterator; /** * @brief iterator over holes contained within the figure */ typedef typename std::list<active_tail_arbitrary*>::const_iterator iteratorHoles; //default constructor inline active_tail_arbitrary() : tailp_(), otherTailp_(), holesList_(), head_() {} //constructor inline active_tail_arbitrary(const vertex_half_edge& vertex, active_tail_arbitrary* otherTailp = 0) : tailp_(), otherTailp_(), holesList_(), head_() { tailp_ = new poly_line_arbitrary; tailp_->points.push_back(vertex.pt); //bool headArray[4] = {false, true, true, true}; bool inverted = vertex.count == -1; head_ = (!vertex.is_vertical) ^ inverted; otherTailp_ = otherTailp; } inline active_tail_arbitrary(Point point, active_tail_arbitrary* otherTailp, bool head = true) : tailp_(), otherTailp_(), holesList_(), head_() { tailp_ = new poly_line_arbitrary; tailp_->points.push_back(point); head_ = head; otherTailp_ = otherTailp; } inline active_tail_arbitrary(active_tail_arbitrary* otherTailp) : tailp_(), otherTailp_(), holesList_(), head_() { tailp_ = otherTailp->tailp_; otherTailp_ = otherTailp; } //copy constructor inline active_tail_arbitrary(const active_tail_arbitrary& that) : tailp_(), otherTailp_(), holesList_(), head_() { (*this) = that; } //destructor inline ~active_tail_arbitrary() { destroyContents(); } //assignment operator inline active_tail_arbitrary& operator=(const active_tail_arbitrary& that) { tailp_ = new poly_line_arbitrary(*(that.tailp_)); head_ = that.head_; otherTailp_ = that.otherTailp_; holesList_ = that.holesList_; return *this; } //equivalence operator inline bool operator==(const active_tail_arbitrary& b) const { return tailp_ == b.tailp_ && head_ == b.head_; } /** * @brief get the pointer to the polyline that this is an active tail of */ inline poly_line_arbitrary* getTail() const { return tailp_; } /** * @brief get the pointer to the polyline at the other end of the chain */ inline poly_line_arbitrary* getOtherTail() const { return otherTailp_->tailp_; } /** * @brief get the pointer to the activetail at the other end of the chain */ inline active_tail_arbitrary* getOtherActiveTail() const { return otherTailp_; } /** * @brief test if another active tail is the other end of the chain */ inline bool isOtherTail(const active_tail_arbitrary& b) const { return &b == otherTailp_; } /** * @brief update this end of chain pointer to new polyline */ inline active_tail_arbitrary& updateTail(poly_line_arbitrary* newTail) { tailp_ = newTail; return *this; } inline bool join(active_tail_arbitrary* tail) { if(tail == otherTailp_) { //std::cout << "joining to other tail!\n"; return false; } if(tail->head_ == head_) { //std::cout << "joining head to head!\n"; return false; } if(!tailp_) { //std::cout << "joining empty tail!\n"; return false; } if(!(otherTailp_->head_)) { otherTailp_->copyHoles(*tail); otherTailp_->copyHoles(*this); } else { tail->otherTailp_->copyHoles(*this); tail->otherTailp_->copyHoles(*tail); } poly_line_arbitrary* tail1 = tailp_; poly_line_arbitrary* tail2 = tail->tailp_; if(head_) std::swap(tail1, tail2); typename std::list<point_data<Unit> >::reverse_iterator riter = tail1->points.rbegin(); typename std::list<point_data<Unit> >::iterator iter = tail2->points.begin(); if(*riter == *iter) { tail1->points.pop_back(); //remove duplicate point } tail1->points.splice(tail1->points.end(), tail2->points); delete tail2; otherTailp_->tailp_ = tail1; tail->otherTailp_->tailp_ = tail1; otherTailp_->otherTailp_ = tail->otherTailp_; tail->otherTailp_->otherTailp_ = otherTailp_; tailp_ = 0; tail->tailp_ = 0; tail->otherTailp_ = 0; otherTailp_ = 0; return true; } /** * @brief associate a hole to this active tail by the specified policy */ inline active_tail_arbitrary* addHole(active_tail_arbitrary* hole) { holesList_.push_back(hole); copyHoles(*hole); copyHoles(*(hole->otherTailp_)); return this; } /** * @brief get the list of holes */ inline const std::list<active_tail_arbitrary*>& getHoles() const { return holesList_; } /** * @brief copy holes from that to this */ inline void copyHoles(active_tail_arbitrary& that) { holesList_.splice(holesList_.end(), that.holesList_); } /** * @brief find out if solid to right */ inline bool solidToRight() const { return !head_; } inline bool solidToLeft() const { return head_; } /** * @brief get vertex */ inline Point getPoint() const { if(head_) return tailp_->points.front(); return tailp_->points.back(); } /** * @brief add a coordinate to the polygon at this active tail end, properly handle degenerate edges by removing redundant coordinate */ inline void pushPoint(Point point) { if(head_) { //if(tailp_->points.size() < 2) { // tailp_->points.push_front(point); // return; //} typename std::list<Point>::iterator iter = tailp_->points.begin(); if(iter == tailp_->points.end()) { tailp_->points.push_front(point); return; } ++iter; if(iter == tailp_->points.end()) { tailp_->points.push_front(point); return; } --iter; if(*iter != point) { tailp_->points.push_front(point); } return; } //if(tailp_->points.size() < 2) { // tailp_->points.push_back(point); // return; //} typename std::list<Point>::reverse_iterator iter = tailp_->points.rbegin(); if(iter == tailp_->points.rend()) { tailp_->points.push_back(point); return; } ++iter; if(iter == tailp_->points.rend()) { tailp_->points.push_back(point); return; } --iter; if(*iter != point) { tailp_->points.push_back(point); } } /** * @brief joins the two chains that the two active tail tails are ends of * checks for closure of figure and writes out polygons appropriately * returns a handle to a hole if one is closed */ template <class cT> static inline active_tail_arbitrary* joinChains(Point point, active_tail_arbitrary* at1, active_tail_arbitrary* at2, bool solid, cT& output) { if(at1->otherTailp_ == at2) { //if(at2->otherTailp_ != at1) std::cout << "half closed error\n"; //we are closing a figure at1->pushPoint(point); at2->pushPoint(point); if(solid) { //we are closing a solid figure, write to output //std::cout << "test1\n"; at1->copyHoles(*(at1->otherTailp_)); typename PolyLineArbitraryByConcept<Unit, typename geometry_concept<typename cT::value_type>::type>::type polyData(at1); //poly_line_arbitrary_polygon_data polyData(at1); //std::cout << "test2\n"; //std::cout << poly << "\n"; //std::cout << "test3\n"; typedef typename cT::value_type result_type; output.push_back(result_type()); assign(output.back(), polyData); //std::cout << "test4\n"; //std::cout << "delete " << at1->otherTailp_ << "\n"; //at1->print(); //at1->otherTailp_->print(); delete at1->otherTailp_; //at1->print(); //at1->otherTailp_->print(); //std::cout << "test5\n"; //std::cout << "delete " << at1 << "\n"; delete at1; //std::cout << "test6\n"; return 0; } else { //we are closing a hole, return the tail end active tail of the figure return at1; } } //we are not closing a figure at1->pushPoint(point); at1->join(at2); delete at1; delete at2; return 0; } inline void destroyContents() { if(otherTailp_) { //std::cout << "delete p " << tailp_ << "\n"; if(tailp_) delete tailp_; tailp_ = 0; otherTailp_->otherTailp_ = 0; otherTailp_->tailp_ = 0; otherTailp_ = 0; } for(typename std::list<active_tail_arbitrary*>::iterator itr = holesList_.begin(); itr != holesList_.end(); ++itr) { //std::cout << "delete p " << (*itr) << "\n"; if(*itr) { if((*itr)->otherTailp_) { delete (*itr)->otherTailp_; (*itr)->otherTailp_ = 0; } delete (*itr); } (*itr) = 0; } holesList_.clear(); } inline void print() { //std::cout << this << " " << tailp_ << " " << otherTailp_ << " " << holesList_.size() << " " << head_ << "\n"; } static inline std::pair<active_tail_arbitrary*, active_tail_arbitrary*> createActiveTailsAsPair(Point point, bool solid, active_tail_arbitrary* phole, bool fractureHoles) { active_tail_arbitrary* at1 = 0; active_tail_arbitrary* at2 = 0; if(phole && fractureHoles) { //std::cout << "adding hole\n"; at1 = phole; //assert solid == false, we should be creating a corner with solid below and to the left if there was a hole at2 = at1->getOtherActiveTail(); at2->pushPoint(point); at1->pushPoint(point); } else { at1 = new active_tail_arbitrary(point, at2, solid); at2 = new active_tail_arbitrary(at1); at1->otherTailp_ = at2; at2->head_ = !solid; if(phole) at2->addHole(phole); //assert fractureHoles == false } return std::pair<active_tail_arbitrary*, active_tail_arbitrary*>(at1, at2); } }; typedef std::vector<std::pair<Point, int> > vertex_arbitrary_count; class less_half_edge_count { private: Point pt_; public: typedef vertex_half_edge first_argument_type; typedef vertex_half_edge second_argument_type; typedef bool result_type; inline less_half_edge_count() : pt_() {} inline less_half_edge_count(Point point) : pt_(point) {} inline bool operator () (const std::pair<Point, int>& elm1, const std::pair<Point, int>& elm2) const { return scanline_base<Unit>::less_slope(pt_.get(HORIZONTAL), pt_.get(VERTICAL), elm1.first, elm2.first); } }; static inline void sort_vertex_arbitrary_count(vertex_arbitrary_count& count, const Point& pt) { less_half_edge_count lfec(pt); polygon_sort(count.begin(), count.end(), lfec); } typedef std::vector<std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*> > incoming_count; class less_incoming_count { private: Point pt_; public: typedef std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*> first_argument_type; typedef std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*> second_argument_type; typedef bool result_type; inline less_incoming_count() : pt_() {} inline less_incoming_count(Point point) : pt_(point) {} inline bool operator () (const std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*>& elm1, const std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*>& elm2) const { Unit dx1 = elm1.first.first.first.get(HORIZONTAL) - elm1.first.first.second.get(HORIZONTAL); Unit dx2 = elm2.first.first.first.get(HORIZONTAL) - elm2.first.first.second.get(HORIZONTAL); Unit dy1 = elm1.first.first.first.get(VERTICAL) - elm1.first.first.second.get(VERTICAL); Unit dy2 = elm2.first.first.first.get(VERTICAL) - elm2.first.first.second.get(VERTICAL); return scanline_base<Unit>::less_slope(dx1, dy1, dx2, dy2); } }; static inline void sort_incoming_count(incoming_count& count, const Point& pt) { less_incoming_count lfec(pt); polygon_sort(count.begin(), count.end(), lfec); } static inline void compact_vertex_arbitrary_count(const Point& pt, vertex_arbitrary_count &count) { if(count.empty()) return; vertex_arbitrary_count tmp; tmp.reserve(count.size()); tmp.push_back(count[0]); //merge duplicates for(std::size_t i = 1; i < count.size(); ++i) { if(!equal_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), tmp[i-1].first, count[i].first)) { tmp.push_back(count[i]); } else { tmp.back().second += count[i].second; } } count.clear(); count.swap(tmp); } // inline std::ostream& operator<< (std::ostream& o, const vertex_arbitrary_count& c) { // for(unsinged int i = 0; i < c.size(); ++i) { // o << c[i].first << " " << c[i].second << " "; // } // return o; // } class vertex_arbitrary_compact { public: Point pt; vertex_arbitrary_count count; inline vertex_arbitrary_compact() : pt(), count() {} inline vertex_arbitrary_compact(const Point& point, const Point& other_point, int countIn) : pt(point), count() { count.push_back(std::pair<Point, int>(other_point, countIn)); } inline vertex_arbitrary_compact(const vertex_half_edge& vertex) : pt(vertex.pt), count() { count.push_back(std::pair<Point, int>(vertex.other_pt, vertex.count)); } inline vertex_arbitrary_compact(const vertex_arbitrary_compact& vertex) : pt(vertex.pt), count(vertex.count) {} inline vertex_arbitrary_compact& operator=(const vertex_arbitrary_compact& vertex){ pt = vertex.pt; count = vertex.count; return *this; } inline bool operator==(const vertex_arbitrary_compact& vertex) const { return pt == vertex.pt && count == vertex.count; } inline bool operator!=(const vertex_arbitrary_compact& vertex) const { return !((*this) == vertex); } inline bool operator<(const vertex_arbitrary_compact& vertex) const { if(pt.get(HORIZONTAL) < vertex.pt.get(HORIZONTAL)) return true; if(pt.get(HORIZONTAL) == vertex.pt.get(HORIZONTAL)) { return pt.get(VERTICAL) < vertex.pt.get(VERTICAL); } return false; } inline bool operator>(const vertex_arbitrary_compact& vertex) const { return vertex < (*this); } inline bool operator<=(const vertex_arbitrary_compact& vertex) const { return !((*this) > vertex); } inline bool operator>=(const vertex_arbitrary_compact& vertex) const { return !((*this) < vertex); } inline bool have_vertex_half_edge(int index) const { return count[index]; } inline vertex_half_edge operator[](int index) const { return vertex_half_edge(pt, count[index]); } }; // inline std::ostream& operator<< (std::ostream& o, const vertex_arbitrary_compact& c) { // o << c.pt << ", " << c.count; // return o; // } protected: //definitions typedef std::map<vertex_half_edge, active_tail_arbitrary*, less_vertex_half_edge> scanline_data; typedef typename scanline_data::iterator iterator; typedef typename scanline_data::const_iterator const_iterator; //data scanline_data scanData_; Unit x_; int justBefore_; int fractureHoles_; public: inline polygon_arbitrary_formation() : scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false), fractureHoles_(0) { less_vertex_half_edge lessElm(&x_, &justBefore_); scanData_ = scanline_data(lessElm); } inline polygon_arbitrary_formation(bool fractureHoles) : scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false), fractureHoles_(fractureHoles) { less_vertex_half_edge lessElm(&x_, &justBefore_); scanData_ = scanline_data(lessElm); } inline polygon_arbitrary_formation(const polygon_arbitrary_formation& that) : scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false), fractureHoles_(0) { (*this) = that; } inline polygon_arbitrary_formation& operator=(const polygon_arbitrary_formation& that) { x_ = that.x_; justBefore_ = that.justBefore_; fractureHoles_ = that.fractureHoles_; less_vertex_half_edge lessElm(&x_, &justBefore_); scanData_ = scanline_data(lessElm); for(const_iterator itr = that.scanData_.begin(); itr != that.scanData_.end(); ++itr){ scanData_.insert(scanData_.end(), *itr); } return *this; } //cT is an output container of Polygon45 or Polygon45WithHoles //iT is an iterator over vertex_half_edge elements //inputBegin - inputEnd is a range of sorted iT that represents //one or more scanline stops worth of data template <class cT, class iT> void scan(cT& output, iT inputBegin, iT inputEnd) { //std::cout << "1\n"; while(inputBegin != inputEnd) { //std::cout << "2\n"; x_ = (*inputBegin).pt.get(HORIZONTAL); //std::cout << "SCAN FORMATION " << x_ << "\n"; //std::cout << "x_ = " << x_ << "\n"; //std::cout << "scan line size: " << scanData_.size() << "\n"; inputBegin = processEvent_(output, inputBegin, inputEnd); } //std::cout << "scan line size: " << scanData_.size() << "\n"; } protected: //functions template <class cT, class cT2> inline std::pair<std::pair<Point, int>, active_tail_arbitrary*> processPoint_(cT& output, cT2& elements, Point point, incoming_count& counts_from_scanline, vertex_arbitrary_count& incoming_count) { //std::cout << "\nAT POINT: " << point << "\n"; //join any closing solid corners std::vector<int> counts; std::vector<int> incoming; std::vector<active_tail_arbitrary*> tails; counts.reserve(counts_from_scanline.size()); tails.reserve(counts_from_scanline.size()); incoming.reserve(incoming_count.size()); for(std::size_t i = 0; i < counts_from_scanline.size(); ++i) { counts.push_back(counts_from_scanline[i].first.second); tails.push_back(counts_from_scanline[i].second); } for(std::size_t i = 0; i < incoming_count.size(); ++i) { incoming.push_back(incoming_count[i].second); if(incoming_count[i].first < point) { incoming.back() = 0; } } active_tail_arbitrary* returnValue = 0; std::pair<Point, int> returnCount(Point(0, 0), 0); int i_size_less_1 = (int)(incoming.size()) -1; int c_size_less_1 = (int)(counts.size()) -1; int i_size = incoming.size(); int c_size = counts.size(); bool have_vertical_tail_from_below = false; if(c_size && scanline_base<Unit>::is_vertical(counts_from_scanline.back().first.first)) { have_vertical_tail_from_below = true; } //assert size = size_less_1 + 1 //std::cout << tails.size() << " " << incoming.size() << " " << counts_from_scanline.size() << " " << incoming_count.size() << "\n"; // for(std::size_t i = 0; i < counts.size(); ++i) { // std::cout << counts_from_scanline[i].first.first.first.get(HORIZONTAL) << ","; // std::cout << counts_from_scanline[i].first.first.first.get(VERTICAL) << " "; // std::cout << counts_from_scanline[i].first.first.second.get(HORIZONTAL) << ","; // std::cout << counts_from_scanline[i].first.first.second.get(VERTICAL) << ":"; // std::cout << counts_from_scanline[i].first.second << " "; // } std::cout << "\n"; // print(incoming_count); { for(int i = 0; i < c_size_less_1; ++i) { //std::cout << i << "\n"; if(counts[i] == -1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < c_size; ++j) { //std::cout << j << "\n"; if(counts[j]) { if(counts[j] == 1) { //std::cout << "case1: " << i << " " << j << "\n"; //if a figure is closed it will be written out by this function to output active_tail_arbitrary::joinChains(point, tails[i], tails[j], true, output); counts[i] = 0; counts[j] = 0; tails[i] = 0; tails[j] = 0; } break; } } } } } //find any pairs of incoming edges that need to create pair for leading solid //std::cout << "checking case2\n"; { for(int i = 0; i < i_size_less_1; ++i) { //std::cout << i << "\n"; if(incoming[i] == 1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < i_size; ++j) { //std::cout << j << "\n"; if(incoming[j]) { //std::cout << incoming[j] << "\n"; if(incoming[j] == -1) { //std::cout << "case2: " << i << " " << j << "\n"; //std::cout << "creating active tail pair\n"; std::pair<active_tail_arbitrary*, active_tail_arbitrary*> tailPair = active_tail_arbitrary::createActiveTailsAsPair(point, true, 0, fractureHoles_ != 0); //tailPair.first->print(); //tailPair.second->print(); if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { //vertical active tail becomes return value returnValue = tailPair.first; returnCount.first = point; returnCount.second = 1; } else { //std::cout << "new element " << j-1 << " " << -1 << "\n"; //std::cout << point << " " << incoming_count[j].first << "\n"; elements.push_back(std::pair<vertex_half_edge, active_tail_arbitrary*>(vertex_half_edge(point, incoming_count[j].first, -1), tailPair.first)); } //std::cout << "new element " << i-1 << " " << 1 << "\n"; //std::cout << point << " " << incoming_count[i].first << "\n"; elements.push_back(std::pair<vertex_half_edge, active_tail_arbitrary*>(vertex_half_edge(point, incoming_count[i].first, 1), tailPair.second)); incoming[i] = 0; incoming[j] = 0; } break; } } } } } //find any active tail that needs to pass through to an incoming edge //we expect to find no more than two pass through //find pass through with solid on top { //std::cout << "checking case 3\n"; for(int i = 0; i < c_size; ++i) { //std::cout << i << "\n"; if(counts[i] != 0) { if(counts[i] == 1) { //std::cout << "fixed i\n"; for(int j = i_size_less_1; j >= 0; --j) { if(incoming[j] != 0) { if(incoming[j] == 1) { //std::cout << "case3: " << i << " " << j << "\n"; //tails[i]->print(); //pass through solid on top tails[i]->pushPoint(point); //std::cout << "after push\n"; if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { returnValue = tails[i]; returnCount.first = point; returnCount.second = -1; } else { elements.push_back(std::pair<vertex_half_edge, active_tail_arbitrary*>(vertex_half_edge(point, incoming_count[j].first, incoming[j]), tails[i])); } tails[i] = 0; counts[i] = 0; incoming[j] = 0; } break; } } } break; } } } //std::cout << "checking case 4\n"; //find pass through with solid on bottom { for(int i = c_size_less_1; i >= 0; --i) { //std::cout << "i = " << i << " with count " << counts[i] << "\n"; if(counts[i] != 0) { if(counts[i] == -1) { for(int j = 0; j < i_size; ++j) { if(incoming[j] != 0) { if(incoming[j] == -1) { //std::cout << "case4: " << i << " " << j << "\n"; //pass through solid on bottom tails[i]->pushPoint(point); if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { returnValue = tails[i]; returnCount.first = point; returnCount.second = 1; } else { //std::cout << "new element " << j-1 << " " << incoming[j] << "\n"; //std::cout << point << " " << incoming_count[j].first << "\n"; elements.push_back(std::pair<vertex_half_edge, active_tail_arbitrary*>(vertex_half_edge(point, incoming_count[j].first, incoming[j]), tails[i])); } tails[i] = 0; counts[i] = 0; incoming[j] = 0; } break; } } } break; } } } //find the end of a hole or the beginning of a hole //find end of a hole { for(int i = 0; i < c_size_less_1; ++i) { if(counts[i] != 0) { for(int j = i+1; j < c_size; ++j) { if(counts[j] != 0) { //std::cout << "case5: " << i << " " << j << "\n"; //we are ending a hole and may potentially close a figure and have to handle the hole returnValue = active_tail_arbitrary::joinChains(point, tails[i], tails[j], false, output); if(returnValue) returnCount.first = point; //std::cout << returnValue << "\n"; tails[i] = 0; tails[j] = 0; counts[i] = 0; counts[j] = 0; break; } } break; } } } //find beginning of a hole { for(int i = 0; i < i_size_less_1; ++i) { if(incoming[i] != 0) { for(int j = i+1; j < i_size; ++j) { if(incoming[j] != 0) { //std::cout << "case6: " << i << " " << j << "\n"; //we are beginning a empty space active_tail_arbitrary* holep = 0; //if(c_size && counts[c_size_less_1] == 0 && // counts_from_scanline[c_size_less_1].first.first.first.get(HORIZONTAL) == point.get(HORIZONTAL)) if(have_vertical_tail_from_below) { holep = tails[c_size_less_1]; tails[c_size_less_1] = 0; have_vertical_tail_from_below = false; } std::pair<active_tail_arbitrary*, active_tail_arbitrary*> tailPair = active_tail_arbitrary::createActiveTailsAsPair(point, false, holep, fractureHoles_ != 0); if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { //std::cout << "vertical element " << point << "\n"; returnValue = tailPair.first; returnCount.first = point; //returnCount = incoming_count[j]; returnCount.second = -1; } else { //std::cout << "new element " << j-1 << " " << incoming[j] << "\n"; //std::cout << point << " " << incoming_count[j].first << "\n"; elements.push_back(std::pair<vertex_half_edge, active_tail_arbitrary*>(vertex_half_edge(point, incoming_count[j].first, incoming[j]), tailPair.first)); } //std::cout << "new element " << i-1 << " " << incoming[i] << "\n"; //std::cout << point << " " << incoming_count[i].first << "\n"; elements.push_back(std::pair<vertex_half_edge, active_tail_arbitrary*>(vertex_half_edge(point, incoming_count[i].first, incoming[i]), tailPair.second)); incoming[i] = 0; incoming[j] = 0; break; } } break; } } } if(have_vertical_tail_from_below) { if(tails.back()) { tails.back()->pushPoint(point); returnValue = tails.back(); returnCount.first = point; returnCount.second = counts.back(); } } //assert that tails, counts and incoming are all null return std::pair<std::pair<Point, int>, active_tail_arbitrary*>(returnCount, returnValue); } static inline void print(const vertex_arbitrary_count& count) { for(unsigned i = 0; i < count.size(); ++i) { //std::cout << count[i].first.get(HORIZONTAL) << ","; //std::cout << count[i].first.get(VERTICAL) << ":"; //std::cout << count[i].second << " "; } //std::cout << "\n"; } static inline void print(const scanline_data& data) { for(typename scanline_data::const_iterator itr = data.begin(); itr != data.end(); ++itr){ //std::cout << itr->first.pt << ", " << itr->first.other_pt << "; "; } //std::cout << "\n"; } template <class cT, class iT> inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { typedef typename high_precision_type<Unit>::type high_precision; //std::cout << "processEvent_\n"; justBefore_ = true; //collect up all elements from the tree that are at the y //values of events in the input queue //create vector of new elements to add into tree active_tail_arbitrary* verticalTail = 0; std::pair<Point, int> verticalCount(Point(0, 0), 0); iT currentIter = inputBegin; std::vector<iterator> elementIters; std::vector<std::pair<vertex_half_edge, active_tail_arbitrary*> > elements; while(currentIter != inputEnd && currentIter->pt.get(HORIZONTAL) == x_) { //std::cout << "loop\n"; Unit currentY = (*currentIter).pt.get(VERTICAL); //std::cout << "current Y " << currentY << "\n"; //std::cout << "scanline size " << scanData_.size() << "\n"; //print(scanData_); iterator iter = lookUp_(currentY); //std::cout << "found element in scanline " << (iter != scanData_.end()) << "\n"; //int counts[4] = {0, 0, 0, 0}; incoming_count counts_from_scanline; //std::cout << "finding elements in tree\n"; //if(iter != scanData_.end()) // std::cout << "first iter y is " << iter->first.evalAtX(x_) << "\n"; while(iter != scanData_.end() && ((iter->first.pt.x() == x_ && iter->first.pt.y() == currentY) || (iter->first.other_pt.x() == x_ && iter->first.other_pt.y() == currentY))) { //iter->first.evalAtX(x_) == (high_precision)currentY) { //std::cout << "loop2\n"; elementIters.push_back(iter); counts_from_scanline.push_back(std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*> (std::pair<std::pair<Point, Point>, int>(std::pair<Point, Point>(iter->first.pt, iter->first.other_pt), iter->first.count), iter->second)); ++iter; } Point currentPoint(x_, currentY); //std::cout << "counts_from_scanline size " << counts_from_scanline.size() << "\n"; sort_incoming_count(counts_from_scanline, currentPoint); vertex_arbitrary_count incoming; //std::cout << "aggregating\n"; do { //std::cout << "loop3\n"; const vertex_half_edge& elem = *currentIter; incoming.push_back(std::pair<Point, int>(elem.other_pt, elem.count)); ++currentIter; } while(currentIter != inputEnd && currentIter->pt.get(VERTICAL) == currentY && currentIter->pt.get(HORIZONTAL) == x_); //print(incoming); sort_vertex_arbitrary_count(incoming, currentPoint); //std::cout << currentPoint.get(HORIZONTAL) << "," << currentPoint.get(VERTICAL) << "\n"; //print(incoming); //std::cout << "incoming counts from input size " << incoming.size() << "\n"; //compact_vertex_arbitrary_count(currentPoint, incoming); vertex_arbitrary_count tmp; tmp.reserve(incoming.size()); for(std::size_t i = 0; i < incoming.size(); ++i) { if(currentPoint < incoming[i].first) { tmp.push_back(incoming[i]); } } incoming.swap(tmp); //std::cout << "incoming counts from input size " << incoming.size() << "\n"; //now counts_from_scanline has the data from the left and //incoming has the data from the right at this point //cancel out any end points if(verticalTail) { //std::cout << "adding vertical tail to counts from scanline\n"; //std::cout << -verticalCount.second << "\n"; counts_from_scanline.push_back(std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*> (std::pair<std::pair<Point, Point>, int>(std::pair<Point, Point>(verticalCount.first, currentPoint), -verticalCount.second), verticalTail)); } if(!incoming.empty() && incoming.back().first.get(HORIZONTAL) == x_) { //std::cout << "inverted vertical event\n"; incoming.back().second *= -1; } //std::cout << "calling processPoint_\n"; std::pair<std::pair<Point, int>, active_tail_arbitrary*> result = processPoint_(output, elements, Point(x_, currentY), counts_from_scanline, incoming); verticalCount = result.first; verticalTail = result.second; //if(verticalTail) { // std::cout << "have vertical tail\n"; // std::cout << verticalCount.second << "\n"; //} if(verticalTail && !(verticalCount.second)) { //we got a hole out of the point we just processed //iter is still at the next y element above the current y value in the tree //std::cout << "checking whether ot handle hole\n"; if(currentIter == inputEnd || currentIter->pt.get(HORIZONTAL) != x_ || scanline_base<Unit>::on_above_or_below(currentIter->pt, half_edge(iter->first.pt, iter->first.other_pt)) != -1) { //(high_precision)(currentIter->pt.get(VERTICAL)) >= iter->first.evalAtX(x_)) { //std::cout << "handle hole here\n"; if(fractureHoles_) { //std::cout << "fracture hole here\n"; //we need to handle the hole now and not at the next input vertex active_tail_arbitrary* at = iter->second; high_precision precise_y = iter->first.evalAtX(x_); Unit fracture_y = convert_high_precision_type<Unit>(precise_y); if(precise_y < fracture_y) --fracture_y; Point point(x_, fracture_y); verticalTail->getOtherActiveTail()->pushPoint(point); iter->second = verticalTail->getOtherActiveTail(); at->pushPoint(point); verticalTail->join(at); delete at; delete verticalTail; verticalTail = 0; } else { //std::cout << "push hole onto list\n"; iter->second->addHole(verticalTail); verticalTail = 0; } } } } //std::cout << "erasing\n"; //erase all elements from the tree for(typename std::vector<iterator>::iterator iter = elementIters.begin(); iter != elementIters.end(); ++iter) { //std::cout << "erasing loop\n"; scanData_.erase(*iter); } //switch comparison tie breaking policy justBefore_ = false; //add new elements into tree //std::cout << "inserting\n"; for(typename std::vector<std::pair<vertex_half_edge, active_tail_arbitrary*> >::iterator iter = elements.begin(); iter != elements.end(); ++iter) { //std::cout << "inserting loop\n"; scanData_.insert(scanData_.end(), *iter); } //std::cout << "end processEvent\n"; return currentIter; } inline iterator lookUp_(Unit y){ //if just before then we need to look from 1 not -1 //std::cout << "just before " << justBefore_ << "\n"; return scanData_.lower_bound(vertex_half_edge(Point(x_, y), Point(x_, y+1), 0)); } public: //test functions template <typename stream_type> static inline bool testPolygonArbitraryFormationRect(stream_type& stdcout) { stdcout << "testing polygon formation\n"; polygon_arbitrary_formation pf(true); std::vector<polygon_data<Unit> > polys; std::vector<vertex_half_edge> data; data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(0, 10), Point(10, 10), -1)); data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(10, 0), Point(10, 10), -1)); data.push_back(vertex_half_edge(Point(10, 10), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(10, 10), Point(0, 10), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } template <typename stream_type> static inline bool testPolygonArbitraryFormationP1(stream_type& stdcout) { stdcout << "testing polygon formation P1\n"; polygon_arbitrary_formation pf(true); std::vector<polygon_data<Unit> > polys; std::vector<vertex_half_edge> data; data.push_back(vertex_half_edge(Point(0, 0), Point(10, 10), 1)); data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(0, 10), Point(10, 20), -1)); data.push_back(vertex_half_edge(Point(10, 10), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(10, 10), Point(10, 20), -1)); data.push_back(vertex_half_edge(Point(10, 20), Point(10, 10), 1)); data.push_back(vertex_half_edge(Point(10, 20), Point(0, 10), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } template <typename stream_type> static inline bool testPolygonArbitraryFormationP2(stream_type& stdcout) { stdcout << "testing polygon formation P2\n"; polygon_arbitrary_formation pf(true); std::vector<polygon_data<Unit> > polys; std::vector<vertex_half_edge> data; data.push_back(vertex_half_edge(Point(-3, 1), Point(2, -4), 1)); data.push_back(vertex_half_edge(Point(-3, 1), Point(-2, 2), -1)); data.push_back(vertex_half_edge(Point(-2, 2), Point(2, 4), -1)); data.push_back(vertex_half_edge(Point(-2, 2), Point(-3, 1), 1)); data.push_back(vertex_half_edge(Point(2, -4), Point(-3, 1), -1)); data.push_back(vertex_half_edge(Point(2, -4), Point(2, 4), -1)); data.push_back(vertex_half_edge(Point(2, 4), Point(-2, 2), 1)); data.push_back(vertex_half_edge(Point(2, 4), Point(2, -4), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } template <typename stream_type> static inline bool testPolygonArbitraryFormationPolys(stream_type& stdcout) { stdcout << "testing polygon formation polys\n"; polygon_arbitrary_formation pf(false); std::vector<polygon_with_holes_data<Unit> > polys; polygon_arbitrary_formation pf2(true); std::vector<polygon_with_holes_data<Unit> > polys2; std::vector<vertex_half_edge> data; data.push_back(vertex_half_edge(Point(0, 0), Point(100, 1), 1)); data.push_back(vertex_half_edge(Point(0, 0), Point(1, 100), -1)); data.push_back(vertex_half_edge(Point(1, 100), Point(0, 0), 1)); data.push_back(vertex_half_edge(Point(1, 100), Point(101, 101), -1)); data.push_back(vertex_half_edge(Point(100, 1), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(100, 1), Point(101, 101), 1)); data.push_back(vertex_half_edge(Point(101, 101), Point(100, 1), -1)); data.push_back(vertex_half_edge(Point(101, 101), Point(1, 100), 1)); data.push_back(vertex_half_edge(Point(2, 2), Point(10, 2), -1)); data.push_back(vertex_half_edge(Point(2, 2), Point(2, 10), -1)); data.push_back(vertex_half_edge(Point(2, 10), Point(2, 2), 1)); data.push_back(vertex_half_edge(Point(2, 10), Point(10, 10), 1)); data.push_back(vertex_half_edge(Point(10, 2), Point(2, 2), 1)); data.push_back(vertex_half_edge(Point(10, 2), Point(10, 10), 1)); data.push_back(vertex_half_edge(Point(10, 10), Point(10, 2), -1)); data.push_back(vertex_half_edge(Point(10, 10), Point(2, 10), -1)); data.push_back(vertex_half_edge(Point(2, 12), Point(10, 12), -1)); data.push_back(vertex_half_edge(Point(2, 12), Point(2, 22), -1)); data.push_back(vertex_half_edge(Point(2, 22), Point(2, 12), 1)); data.push_back(vertex_half_edge(Point(2, 22), Point(10, 22), 1)); data.push_back(vertex_half_edge(Point(10, 12), Point(2, 12), 1)); data.push_back(vertex_half_edge(Point(10, 12), Point(10, 22), 1)); data.push_back(vertex_half_edge(Point(10, 22), Point(10, 12), -1)); data.push_back(vertex_half_edge(Point(10, 22), Point(2, 22), -1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } pf2.scan(polys2, data.begin(), data.end()); stdcout << "result size: " << polys2.size() << "\n"; for(std::size_t i = 0; i < polys2.size(); ++i) { stdcout << polys2[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } template <typename stream_type> static inline bool testPolygonArbitraryFormationSelfTouch1(stream_type& stdcout) { stdcout << "testing polygon formation self touch 1\n"; polygon_arbitrary_formation pf(true); std::vector<polygon_data<Unit> > polys; std::vector<vertex_half_edge> data; data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(0, 10), Point(5, 10), -1)); data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(10, 0), Point(10, 5), -1)); data.push_back(vertex_half_edge(Point(10, 5), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(10, 5), Point(5, 5), 1)); data.push_back(vertex_half_edge(Point(5, 10), Point(5, 5), 1)); data.push_back(vertex_half_edge(Point(5, 10), Point(0, 10), 1)); data.push_back(vertex_half_edge(Point(5, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(5, 2), Point(7, 2), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(5, 10), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(5, 2), 1)); data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(7, 2), Point(5, 2), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } template <typename stream_type> static inline bool testPolygonArbitraryFormationSelfTouch2(stream_type& stdcout) { stdcout << "testing polygon formation self touch 2\n"; polygon_arbitrary_formation pf(true); std::vector<polygon_data<Unit> > polys; std::vector<vertex_half_edge> data; data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(0, 10), Point(5, 10), -1)); data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(10, 0), Point(10, 5), -1)); data.push_back(vertex_half_edge(Point(10, 5), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(10, 5), Point(5, 5), 1)); data.push_back(vertex_half_edge(Point(5, 10), Point(4, 1), -1)); data.push_back(vertex_half_edge(Point(5, 10), Point(0, 10), 1)); data.push_back(vertex_half_edge(Point(4, 1), Point(5, 10), 1)); data.push_back(vertex_half_edge(Point(4, 1), Point(7, 2), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(7, 2), Point(4, 1), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } template <typename stream_type> static inline bool testPolygonArbitraryFormationSelfTouch3(stream_type& stdcout) { stdcout << "testing polygon formation self touch 3\n"; polygon_arbitrary_formation pf(true); std::vector<polygon_data<Unit> > polys; std::vector<vertex_half_edge> data; data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(0, 10), Point(6, 10), -1)); data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(10, 0), Point(10, 5), -1)); data.push_back(vertex_half_edge(Point(10, 5), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(10, 5), Point(5, 5), 1)); data.push_back(vertex_half_edge(Point(6, 10), Point(4, 1), -1)); data.push_back(vertex_half_edge(Point(6, 10), Point(0, 10), 1)); data.push_back(vertex_half_edge(Point(4, 1), Point(6, 10), 1)); data.push_back(vertex_half_edge(Point(4, 1), Point(7, 2), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(7, 2), Point(4, 1), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } template <typename stream_type> static inline bool testPolygonArbitraryFormationColinear(stream_type& stdcout) { stdcout << "testing polygon formation colinear 3\n"; stdcout << "Polygon Set Data { <-3 2, -2 2>:1 <-3 2, -1 4>:-1 <-2 2, 0 2>:1 <-1 4, 0 2>:-1 } \n"; polygon_arbitrary_formation pf(true); std::vector<polygon_data<Unit> > polys; std::vector<vertex_half_edge> data; data.push_back(vertex_half_edge(Point(-3, 2), Point(-2, 2), 1)); data.push_back(vertex_half_edge(Point(-2, 2), Point(-3, 2), -1)); data.push_back(vertex_half_edge(Point(-3, 2), Point(-1, 4), -1)); data.push_back(vertex_half_edge(Point(-1, 4), Point(-3, 2), 1)); data.push_back(vertex_half_edge(Point(-2, 2), Point(0, 2), 1)); data.push_back(vertex_half_edge(Point(0, 2), Point(-2, 2), -1)); data.push_back(vertex_half_edge(Point(-1, 4), Point(0, 2), -1)); data.push_back(vertex_half_edge(Point(0, 2), Point(-1, 4), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; } template <typename stream_type> static inline bool testSegmentIntersection(stream_type& stdcout) { stdcout << "testing segment intersection\n"; half_edge he1, he2; he1.first = Point(0, 0); he1.second = Point(10, 10); he2.first = Point(0, 0); he2.second = Point(10, 20); Point result; bool b = scanline_base<Unit>::compute_intersection(result, he1, he2); if(!b || result != Point(0, 0)) return false; he1.first = Point(0, 10); b = scanline_base<Unit>::compute_intersection(result, he1, he2); if(!b || result != Point(5, 10)) return false; he1.first = Point(0, 11); b = scanline_base<Unit>::compute_intersection(result, he1, he2); if(!b || result != Point(5, 10)) return false; he1.first = Point(0, 0); he1.second = Point(1, 9); he2.first = Point(0, 9); he2.second = Point(1, 0); b = scanline_base<Unit>::compute_intersection(result, he1, he2); if(!b || result != Point(0, 4)) return false; he1.first = Point(0, -10); he1.second = Point(1, -1); he2.first = Point(0, -1); he2.second = Point(1, -10); b = scanline_base<Unit>::compute_intersection(result, he1, he2); if(!b || result != Point(0, -5)) return false; he1.first = Point((std::numeric_limits<int>::max)(), (std::numeric_limits<int>::max)()-1); he1.second = Point((std::numeric_limits<int>::min)(), (std::numeric_limits<int>::max)()); //he1.second = Point(0, (std::numeric_limits<int>::max)()); he2.first = Point((std::numeric_limits<int>::max)()-1, (std::numeric_limits<int>::max)()); he2.second = Point((std::numeric_limits<int>::max)(), (std::numeric_limits<int>::min)()); //he2.second = Point((std::numeric_limits<int>::max)(), 0); b = scanline_base<Unit>::compute_intersection(result, he1, he2); //b is false because of overflow error he1.first = Point(1000, 2000); he1.second = Point(1010, 2010); he2.first = Point(1000, 2000); he2.second = Point(1010, 2020); b = scanline_base<Unit>::compute_intersection(result, he1, he2); if(!b || result != Point(1000, 2000)) return false; return b; } }; template <typename Unit> class poly_line_arbitrary_hole_data { private: typedef typename polygon_arbitrary_formation<Unit>::active_tail_arbitrary active_tail_arbitrary; active_tail_arbitrary* p_; public: typedef point_data<Unit> Point; typedef Point point_type; typedef Unit coordinate_type; typedef typename active_tail_arbitrary::iterator iterator_type; //typedef iterator_points_to_compact<iterator_type, Point> compact_iterator_type; typedef iterator_type iterator; inline poly_line_arbitrary_hole_data() : p_(0) {} inline poly_line_arbitrary_hole_data(active_tail_arbitrary* p) : p_(p) {} //use default copy and assign inline iterator begin() const { return p_->getTail()->begin(); } inline iterator end() const { return p_->getTail()->end(); } inline std::size_t size() const { return 0; } }; template <typename Unit> class poly_line_arbitrary_polygon_data { private: typedef typename polygon_arbitrary_formation<Unit>::active_tail_arbitrary active_tail_arbitrary; active_tail_arbitrary* p_; public: typedef point_data<Unit> Point; typedef Point point_type; typedef Unit coordinate_type; typedef typename active_tail_arbitrary::iterator iterator_type; //typedef iterator_points_to_compact<iterator_type, Point> compact_iterator_type; typedef typename coordinate_traits<Unit>::coordinate_distance area_type; class iterator_holes_type { private: typedef poly_line_arbitrary_hole_data<Unit> holeType; mutable holeType hole_; typename active_tail_arbitrary::iteratorHoles itr_; public: typedef std::forward_iterator_tag iterator_category; typedef holeType value_type; typedef std::ptrdiff_t difference_type; typedef const holeType* pointer; //immutable typedef const holeType& reference; //immutable inline iterator_holes_type() : hole_(), itr_() {} inline iterator_holes_type(typename active_tail_arbitrary::iteratorHoles itr) : hole_(), itr_(itr) {} inline iterator_holes_type(const iterator_holes_type& that) : hole_(that.hole_), itr_(that.itr_) {} inline iterator_holes_type& operator=(const iterator_holes_type& that) { itr_ = that.itr_; return *this; } inline bool operator==(const iterator_holes_type& that) { return itr_ == that.itr_; } inline bool operator!=(const iterator_holes_type& that) { return itr_ != that.itr_; } inline iterator_holes_type& operator++() { ++itr_; return *this; } inline const iterator_holes_type operator++(int) { iterator_holes_type tmp = *this; ++(*this); return tmp; } inline reference operator*() { hole_ = holeType(*itr_); return hole_; } }; typedef poly_line_arbitrary_hole_data<Unit> hole_type; inline poly_line_arbitrary_polygon_data() : p_(0) {} inline poly_line_arbitrary_polygon_data(active_tail_arbitrary* p) : p_(p) {} //use default copy and assign inline iterator_type begin() const { return p_->getTail()->begin(); } inline iterator_type end() const { return p_->getTail()->end(); } //inline compact_iterator_type begin_compact() const { return p_->getTail()->begin(); } //inline compact_iterator_type end_compact() const { return p_->getTail()->end(); } inline iterator_holes_type begin_holes() const { return iterator_holes_type(p_->getHoles().begin()); } inline iterator_holes_type end_holes() const { return iterator_holes_type(p_->getHoles().end()); } inline active_tail_arbitrary* yield() { return p_; } //stub out these four required functions that will not be used but are needed for the interface inline std::size_t size_holes() const { return 0; } inline std::size_t size() const { return 0; } }; template <typename Unit> class trapezoid_arbitrary_formation : public polygon_arbitrary_formation<Unit> { private: typedef typename scanline_base<Unit>::Point Point; typedef typename scanline_base<Unit>::half_edge half_edge; typedef typename scanline_base<Unit>::vertex_half_edge vertex_half_edge; typedef typename scanline_base<Unit>::less_vertex_half_edge less_vertex_half_edge; typedef typename polygon_arbitrary_formation<Unit>::poly_line_arbitrary poly_line_arbitrary; typedef typename polygon_arbitrary_formation<Unit>::active_tail_arbitrary active_tail_arbitrary; typedef std::vector<std::pair<Point, int> > vertex_arbitrary_count; typedef typename polygon_arbitrary_formation<Unit>::less_half_edge_count less_half_edge_count; typedef std::vector<std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*> > incoming_count; typedef typename polygon_arbitrary_formation<Unit>::less_incoming_count less_incoming_count; typedef typename polygon_arbitrary_formation<Unit>::vertex_arbitrary_compact vertex_arbitrary_compact; private: //definitions typedef std::map<vertex_half_edge, active_tail_arbitrary*, less_vertex_half_edge> scanline_data; typedef typename scanline_data::iterator iterator; typedef typename scanline_data::const_iterator const_iterator; //data public: inline trapezoid_arbitrary_formation() : polygon_arbitrary_formation<Unit>() {} inline trapezoid_arbitrary_formation(const trapezoid_arbitrary_formation& that) : polygon_arbitrary_formation<Unit>(that) {} inline trapezoid_arbitrary_formation& operator=(const trapezoid_arbitrary_formation& that) { * static_cast<polygon_arbitrary_formation<Unit>*>(this) = * static_cast<polygon_arbitrary_formation<Unit>*>(&that); return *this; } //cT is an output container of Polygon45 or Polygon45WithHoles //iT is an iterator over vertex_half_edge elements //inputBegin - inputEnd is a range of sorted iT that represents //one or more scanline stops worth of data template <class cT, class iT> void scan(cT& output, iT inputBegin, iT inputEnd) { //std::cout << "1\n"; while(inputBegin != inputEnd) { //std::cout << "2\n"; polygon_arbitrary_formation<Unit>::x_ = (*inputBegin).pt.get(HORIZONTAL); //std::cout << "SCAN FORMATION " << x_ << "\n"; //std::cout << "x_ = " << x_ << "\n"; //std::cout << "scan line size: " << scanData_.size() << "\n"; inputBegin = processEvent_(output, inputBegin, inputEnd); } //std::cout << "scan line size: " << scanData_.size() << "\n"; } private: //functions inline void getVerticalPair_(std::pair<active_tail_arbitrary*, active_tail_arbitrary*>& verticalPair, iterator previter) { active_tail_arbitrary* iterTail = (*previter).second; Point prevPoint(polygon_arbitrary_formation<Unit>::x_, convert_high_precision_type<Unit>(previter->first.evalAtX(polygon_arbitrary_formation<Unit>::x_))); iterTail->pushPoint(prevPoint); std::pair<active_tail_arbitrary*, active_tail_arbitrary*> tailPair = active_tail_arbitrary::createActiveTailsAsPair(prevPoint, true, 0, false); verticalPair.first = iterTail; verticalPair.second = tailPair.first; (*previter).second = tailPair.second; } template <class cT, class cT2> inline std::pair<std::pair<Point, int>, active_tail_arbitrary*> processPoint_(cT& output, cT2& elements, std::pair<active_tail_arbitrary*, active_tail_arbitrary*>& verticalPair, iterator previter, Point point, incoming_count& counts_from_scanline, vertex_arbitrary_count& incoming_count) { //std::cout << "\nAT POINT: " << point << "\n"; //join any closing solid corners std::vector<int> counts; std::vector<int> incoming; std::vector<active_tail_arbitrary*> tails; counts.reserve(counts_from_scanline.size()); tails.reserve(counts_from_scanline.size()); incoming.reserve(incoming_count.size()); for(std::size_t i = 0; i < counts_from_scanline.size(); ++i) { counts.push_back(counts_from_scanline[i].first.second); tails.push_back(counts_from_scanline[i].second); } for(std::size_t i = 0; i < incoming_count.size(); ++i) { incoming.push_back(incoming_count[i].second); if(incoming_count[i].first < point) { incoming.back() = 0; } } active_tail_arbitrary* returnValue = 0; std::pair<active_tail_arbitrary*, active_tail_arbitrary*> verticalPairOut; verticalPairOut.first = 0; verticalPairOut.second = 0; std::pair<Point, int> returnCount(Point(0, 0), 0); int i_size_less_1 = (int)(incoming.size()) -1; int c_size_less_1 = (int)(counts.size()) -1; int i_size = incoming.size(); int c_size = counts.size(); bool have_vertical_tail_from_below = false; if(c_size && scanline_base<Unit>::is_vertical(counts_from_scanline.back().first.first)) { have_vertical_tail_from_below = true; } //assert size = size_less_1 + 1 //std::cout << tails.size() << " " << incoming.size() << " " << counts_from_scanline.size() << " " << incoming_count.size() << "\n"; // for(std::size_t i = 0; i < counts.size(); ++i) { // std::cout << counts_from_scanline[i].first.first.first.get(HORIZONTAL) << ","; // std::cout << counts_from_scanline[i].first.first.first.get(VERTICAL) << " "; // std::cout << counts_from_scanline[i].first.first.second.get(HORIZONTAL) << ","; // std::cout << counts_from_scanline[i].first.first.second.get(VERTICAL) << ":"; // std::cout << counts_from_scanline[i].first.second << " "; // } std::cout << "\n"; // print(incoming_count); { for(int i = 0; i < c_size_less_1; ++i) { //std::cout << i << "\n"; if(counts[i] == -1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < c_size; ++j) { //std::cout << j << "\n"; if(counts[j]) { if(counts[j] == 1) { //std::cout << "case1: " << i << " " << j << "\n"; //if a figure is closed it will be written out by this function to output active_tail_arbitrary::joinChains(point, tails[i], tails[j], true, output); counts[i] = 0; counts[j] = 0; tails[i] = 0; tails[j] = 0; } break; } } } } } //find any pairs of incoming edges that need to create pair for leading solid //std::cout << "checking case2\n"; { for(int i = 0; i < i_size_less_1; ++i) { //std::cout << i << "\n"; if(incoming[i] == 1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < i_size; ++j) { //std::cout << j << "\n"; if(incoming[j]) { //std::cout << incoming[j] << "\n"; if(incoming[j] == -1) { //std::cout << "case2: " << i << " " << j << "\n"; //std::cout << "creating active tail pair\n"; std::pair<active_tail_arbitrary*, active_tail_arbitrary*> tailPair = active_tail_arbitrary::createActiveTailsAsPair(point, true, 0, polygon_arbitrary_formation<Unit>::fractureHoles_ != 0); //tailPair.first->print(); //tailPair.second->print(); if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { //vertical active tail becomes return value returnValue = tailPair.first; returnCount.first = point; returnCount.second = 1; } else { //std::cout << "new element " << j-1 << " " << -1 << "\n"; //std::cout << point << " " << incoming_count[j].first << "\n"; elements.push_back(std::pair<vertex_half_edge, active_tail_arbitrary*>(vertex_half_edge(point, incoming_count[j].first, -1), tailPair.first)); } //std::cout << "new element " << i-1 << " " << 1 << "\n"; //std::cout << point << " " << incoming_count[i].first << "\n"; elements.push_back(std::pair<vertex_half_edge, active_tail_arbitrary*>(vertex_half_edge(point, incoming_count[i].first, 1), tailPair.second)); incoming[i] = 0; incoming[j] = 0; } break; } } } } } //find any active tail that needs to pass through to an incoming edge //we expect to find no more than two pass through //find pass through with solid on top { //std::cout << "checking case 3\n"; for(int i = 0; i < c_size; ++i) { //std::cout << i << "\n"; if(counts[i] != 0) { if(counts[i] == 1) { //std::cout << "fixed i\n"; for(int j = i_size_less_1; j >= 0; --j) { if(incoming[j] != 0) { if(incoming[j] == 1) { //std::cout << "case3: " << i << " " << j << "\n"; //tails[i]->print(); //pass through solid on top tails[i]->pushPoint(point); //std::cout << "after push\n"; if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { returnValue = tails[i]; returnCount.first = point; returnCount.second = -1; } else { std::pair<active_tail_arbitrary*, active_tail_arbitrary*> tailPair = active_tail_arbitrary::createActiveTailsAsPair(point, true, 0, false); verticalPairOut.first = tails[i]; verticalPairOut.second = tailPair.first; elements.push_back(std::pair<vertex_half_edge, active_tail_arbitrary*>(vertex_half_edge(point, incoming_count[j].first, incoming[j]), tailPair.second)); } tails[i] = 0; counts[i] = 0; incoming[j] = 0; } break; } } } break; } } } //std::cout << "checking case 4\n"; //find pass through with solid on bottom { for(int i = c_size_less_1; i >= 0; --i) { //std::cout << "i = " << i << " with count " << counts[i] << "\n"; if(counts[i] != 0) { if(counts[i] == -1) { for(int j = 0; j < i_size; ++j) { if(incoming[j] != 0) { if(incoming[j] == -1) { //std::cout << "case4: " << i << " " << j << "\n"; //pass through solid on bottom //if count from scanline is vertical if(i == c_size_less_1 && counts_from_scanline[i].first.first.first.get(HORIZONTAL) == point.get(HORIZONTAL)) { //if incoming count is vertical if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { returnValue = tails[i]; returnCount.first = point; returnCount.second = 1; } else { tails[i]->pushPoint(point); elements.push_back(std::pair<vertex_half_edge, active_tail_arbitrary*>(vertex_half_edge(point, incoming_count[j].first, incoming[j]), tails[i])); } } else if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { if(verticalPair.first == 0) { getVerticalPair_(verticalPair, previter); } active_tail_arbitrary::joinChains(point, tails[i], verticalPair.first, true, output); returnValue = verticalPair.second; returnCount.first = point; returnCount.second = 1; } else { //neither is vertical if(verticalPair.first == 0) { getVerticalPair_(verticalPair, previter); } active_tail_arbitrary::joinChains(point, tails[i], verticalPair.first, true, output); verticalPair.second->pushPoint(point); elements.push_back(std::pair<vertex_half_edge, active_tail_arbitrary*>(vertex_half_edge(point, incoming_count[j].first, incoming[j]), verticalPair.second)); } tails[i] = 0; counts[i] = 0; incoming[j] = 0; } break; } } } break; } } } //find the end of a hole or the beginning of a hole //find end of a hole { for(int i = 0; i < c_size_less_1; ++i) { if(counts[i] != 0) { for(int j = i+1; j < c_size; ++j) { if(counts[j] != 0) { //std::cout << "case5: " << i << " " << j << "\n"; //we are ending a hole and may potentially close a figure and have to handle the hole tails[i]->pushPoint(point); verticalPairOut.first = tails[i]; if(j == c_size_less_1 && counts_from_scanline[j].first.first.first.get(HORIZONTAL) == point.get(HORIZONTAL)) { verticalPairOut.second = tails[j]; } else { //need to close a trapezoid below if(verticalPair.first == 0) { getVerticalPair_(verticalPair, previter); } active_tail_arbitrary::joinChains(point, tails[j], verticalPair.first, true, output); verticalPairOut.second = verticalPair.second; } tails[i] = 0; tails[j] = 0; counts[i] = 0; counts[j] = 0; break; } } break; } } } //find beginning of a hole { for(int i = 0; i < i_size_less_1; ++i) { if(incoming[i] != 0) { for(int j = i+1; j < i_size; ++j) { if(incoming[j] != 0) { //std::cout << "case6: " << i << " " << j << "\n"; //we are beginning a empty space if(verticalPair.first == 0) { getVerticalPair_(verticalPair, previter); } verticalPair.second->pushPoint(point); if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { returnValue = verticalPair.first; returnCount.first = point; returnCount.second = -1; } else { std::pair<active_tail_arbitrary*, active_tail_arbitrary*> tailPair = active_tail_arbitrary::createActiveTailsAsPair(point, false, 0, false); elements.push_back(std::pair<vertex_half_edge, active_tail_arbitrary*>(vertex_half_edge(point, incoming_count[j].first, incoming[j]), tailPair.second)); verticalPairOut.second = tailPair.first; verticalPairOut.first = verticalPair.first; } elements.push_back(std::pair<vertex_half_edge, active_tail_arbitrary*>(vertex_half_edge(point, incoming_count[i].first, incoming[i]), verticalPair.second)); incoming[i] = 0; incoming[j] = 0; break; } } break; } } } if(have_vertical_tail_from_below) { if(tails.back()) { tails.back()->pushPoint(point); returnValue = tails.back(); returnCount.first = point; returnCount.second = counts.back(); } } verticalPair = verticalPairOut; //assert that tails, counts and incoming are all null return std::pair<std::pair<Point, int>, active_tail_arbitrary*>(returnCount, returnValue); } static inline void print(const vertex_arbitrary_count& count) { for(unsigned i = 0; i < count.size(); ++i) { //std::cout << count[i].first.get(HORIZONTAL) << ","; //std::cout << count[i].first.get(VERTICAL) << ":"; //std::cout << count[i].second << " "; } //std::cout << "\n"; } static inline void print(const scanline_data& data) { for(typename scanline_data::const_iterator itr = data.begin(); itr != data.end(); ++itr){ //std::cout << itr->first.pt << ", " << itr->first.other_pt << "; "; } //std::cout << "\n"; } template <class cT, class iT> inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { //typedef typename high_precision_type<Unit>::type high_precision; //std::cout << "processEvent_\n"; polygon_arbitrary_formation<Unit>::justBefore_ = true; //collect up all elements from the tree that are at the y //values of events in the input queue //create vector of new elements to add into tree active_tail_arbitrary* verticalTail = 0; std::pair<active_tail_arbitrary*, active_tail_arbitrary*> verticalPair; std::pair<Point, int> verticalCount(Point(0, 0), 0); iT currentIter = inputBegin; std::vector<iterator> elementIters; std::vector<std::pair<vertex_half_edge, active_tail_arbitrary*> > elements; while(currentIter != inputEnd && currentIter->pt.get(HORIZONTAL) == polygon_arbitrary_formation<Unit>::x_) { //std::cout << "loop\n"; Unit currentY = (*currentIter).pt.get(VERTICAL); //std::cout << "current Y " << currentY << "\n"; //std::cout << "scanline size " << scanData_.size() << "\n"; //print(scanData_); iterator iter = this->lookUp_(currentY); //std::cout << "found element in scanline " << (iter != scanData_.end()) << "\n"; //int counts[4] = {0, 0, 0, 0}; incoming_count counts_from_scanline; //std::cout << "finding elements in tree\n"; //if(iter != scanData_.end()) // std::cout << "first iter y is " << iter->first.evalAtX(x_) << "\n"; iterator previter = iter; if(previter != polygon_arbitrary_formation<Unit>::scanData_.end() && previter->first.evalAtX(polygon_arbitrary_formation<Unit>::x_) >= currentY && previter != polygon_arbitrary_formation<Unit>::scanData_.begin()) --previter; while(iter != polygon_arbitrary_formation<Unit>::scanData_.end() && ((iter->first.pt.x() == polygon_arbitrary_formation<Unit>::x_ && iter->first.pt.y() == currentY) || (iter->first.other_pt.x() == polygon_arbitrary_formation<Unit>::x_ && iter->first.other_pt.y() == currentY))) { //iter->first.evalAtX(polygon_arbitrary_formation<Unit>::x_) == (high_precision)currentY) { //std::cout << "loop2\n"; elementIters.push_back(iter); counts_from_scanline.push_back(std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*> (std::pair<std::pair<Point, Point>, int>(std::pair<Point, Point>(iter->first.pt, iter->first.other_pt), iter->first.count), iter->second)); ++iter; } Point currentPoint(polygon_arbitrary_formation<Unit>::x_, currentY); //std::cout << "counts_from_scanline size " << counts_from_scanline.size() << "\n"; this->sort_incoming_count(counts_from_scanline, currentPoint); vertex_arbitrary_count incoming; //std::cout << "aggregating\n"; do { //std::cout << "loop3\n"; const vertex_half_edge& elem = *currentIter; incoming.push_back(std::pair<Point, int>(elem.other_pt, elem.count)); ++currentIter; } while(currentIter != inputEnd && currentIter->pt.get(VERTICAL) == currentY && currentIter->pt.get(HORIZONTAL) == polygon_arbitrary_formation<Unit>::x_); //print(incoming); this->sort_vertex_arbitrary_count(incoming, currentPoint); //std::cout << currentPoint.get(HORIZONTAL) << "," << currentPoint.get(VERTICAL) << "\n"; //print(incoming); //std::cout << "incoming counts from input size " << incoming.size() << "\n"; //compact_vertex_arbitrary_count(currentPoint, incoming); vertex_arbitrary_count tmp; tmp.reserve(incoming.size()); for(std::size_t i = 0; i < incoming.size(); ++i) { if(currentPoint < incoming[i].first) { tmp.push_back(incoming[i]); } } incoming.swap(tmp); //std::cout << "incoming counts from input size " << incoming.size() << "\n"; //now counts_from_scanline has the data from the left and //incoming has the data from the right at this point //cancel out any end points if(verticalTail) { //std::cout << "adding vertical tail to counts from scanline\n"; //std::cout << -verticalCount.second << "\n"; counts_from_scanline.push_back(std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*> (std::pair<std::pair<Point, Point>, int>(std::pair<Point, Point>(verticalCount.first, currentPoint), -verticalCount.second), verticalTail)); } if(!incoming.empty() && incoming.back().first.get(HORIZONTAL) == polygon_arbitrary_formation<Unit>::x_) { //std::cout << "inverted vertical event\n"; incoming.back().second *= -1; } //std::cout << "calling processPoint_\n"; std::pair<std::pair<Point, int>, active_tail_arbitrary*> result = processPoint_(output, elements, verticalPair, previter, Point(polygon_arbitrary_formation<Unit>::x_, currentY), counts_from_scanline, incoming); verticalCount = result.first; verticalTail = result.second; if(verticalPair.first != 0 && iter != polygon_arbitrary_formation<Unit>::scanData_.end() && (currentIter == inputEnd || currentIter->pt.x() != polygon_arbitrary_formation<Unit>::x_ || currentIter->pt.y() > (*iter).first.evalAtX(polygon_arbitrary_formation<Unit>::x_))) { //splice vertical pair into edge above active_tail_arbitrary* tailabove = (*iter).second; Point point(polygon_arbitrary_formation<Unit>::x_, convert_high_precision_type<Unit>((*iter).first.evalAtX(polygon_arbitrary_formation<Unit>::x_))); verticalPair.second->pushPoint(point); active_tail_arbitrary::joinChains(point, tailabove, verticalPair.first, true, output); (*iter).second = verticalPair.second; verticalPair.first = 0; verticalPair.second = 0; } } //std::cout << "erasing\n"; //erase all elements from the tree for(typename std::vector<iterator>::iterator iter = elementIters.begin(); iter != elementIters.end(); ++iter) { //std::cout << "erasing loop\n"; polygon_arbitrary_formation<Unit>::scanData_.erase(*iter); } //switch comparison tie breaking policy polygon_arbitrary_formation<Unit>::justBefore_ = false; //add new elements into tree //std::cout << "inserting\n"; for(typename std::vector<std::pair<vertex_half_edge, active_tail_arbitrary*> >::iterator iter = elements.begin(); iter != elements.end(); ++iter) { //std::cout << "inserting loop\n"; polygon_arbitrary_formation<Unit>::scanData_.insert(polygon_arbitrary_formation<Unit>::scanData_.end(), *iter); } //std::cout << "end processEvent\n"; return currentIter; } public: template <typename stream_type> static inline bool testTrapezoidArbitraryFormationRect(stream_type& stdcout) { stdcout << "testing trapezoid formation\n"; trapezoid_arbitrary_formation pf; std::vector<polygon_data<Unit> > polys; std::vector<vertex_half_edge> data; data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(0, 10), Point(10, 10), -1)); data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(10, 0), Point(10, 10), -1)); data.push_back(vertex_half_edge(Point(10, 10), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(10, 10), Point(0, 10), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing trapezoid formation\n"; return true; } template <typename stream_type> static inline bool testTrapezoidArbitraryFormationP1(stream_type& stdcout) { stdcout << "testing trapezoid formation P1\n"; trapezoid_arbitrary_formation pf; std::vector<polygon_data<Unit> > polys; std::vector<vertex_half_edge> data; data.push_back(vertex_half_edge(Point(0, 0), Point(10, 10), 1)); data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(0, 10), Point(10, 20), -1)); data.push_back(vertex_half_edge(Point(10, 10), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(10, 10), Point(10, 20), -1)); data.push_back(vertex_half_edge(Point(10, 20), Point(10, 10), 1)); data.push_back(vertex_half_edge(Point(10, 20), Point(0, 10), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing trapezoid formation\n"; return true; } template <typename stream_type> static inline bool testTrapezoidArbitraryFormationP2(stream_type& stdcout) { stdcout << "testing trapezoid formation P2\n"; trapezoid_arbitrary_formation pf; std::vector<polygon_data<Unit> > polys; std::vector<vertex_half_edge> data; data.push_back(vertex_half_edge(Point(-3, 1), Point(2, -4), 1)); data.push_back(vertex_half_edge(Point(-3, 1), Point(-2, 2), -1)); data.push_back(vertex_half_edge(Point(-2, 2), Point(2, 4), -1)); data.push_back(vertex_half_edge(Point(-2, 2), Point(-3, 1), 1)); data.push_back(vertex_half_edge(Point(2, -4), Point(-3, 1), -1)); data.push_back(vertex_half_edge(Point(2, -4), Point(2, 4), -1)); data.push_back(vertex_half_edge(Point(2, 4), Point(-2, 2), 1)); data.push_back(vertex_half_edge(Point(2, 4), Point(2, -4), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing trapezoid formation\n"; return true; } template <typename stream_type> static inline bool testTrapezoidArbitraryFormationPolys(stream_type& stdcout) { stdcout << "testing trapezoid formation polys\n"; trapezoid_arbitrary_formation pf; std::vector<polygon_with_holes_data<Unit> > polys; //trapezoid_arbitrary_formation pf2(true); //std::vector<polygon_with_holes_data<Unit> > polys2; std::vector<vertex_half_edge> data; data.push_back(vertex_half_edge(Point(0, 0), Point(100, 1), 1)); data.push_back(vertex_half_edge(Point(0, 0), Point(1, 100), -1)); data.push_back(vertex_half_edge(Point(1, 100), Point(0, 0), 1)); data.push_back(vertex_half_edge(Point(1, 100), Point(101, 101), -1)); data.push_back(vertex_half_edge(Point(100, 1), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(100, 1), Point(101, 101), 1)); data.push_back(vertex_half_edge(Point(101, 101), Point(100, 1), -1)); data.push_back(vertex_half_edge(Point(101, 101), Point(1, 100), 1)); data.push_back(vertex_half_edge(Point(2, 2), Point(10, 2), -1)); data.push_back(vertex_half_edge(Point(2, 2), Point(2, 10), -1)); data.push_back(vertex_half_edge(Point(2, 10), Point(2, 2), 1)); data.push_back(vertex_half_edge(Point(2, 10), Point(10, 10), 1)); data.push_back(vertex_half_edge(Point(10, 2), Point(2, 2), 1)); data.push_back(vertex_half_edge(Point(10, 2), Point(10, 10), 1)); data.push_back(vertex_half_edge(Point(10, 10), Point(10, 2), -1)); data.push_back(vertex_half_edge(Point(10, 10), Point(2, 10), -1)); data.push_back(vertex_half_edge(Point(2, 12), Point(10, 12), -1)); data.push_back(vertex_half_edge(Point(2, 12), Point(2, 22), -1)); data.push_back(vertex_half_edge(Point(2, 22), Point(2, 12), 1)); data.push_back(vertex_half_edge(Point(2, 22), Point(10, 22), 1)); data.push_back(vertex_half_edge(Point(10, 12), Point(2, 12), 1)); data.push_back(vertex_half_edge(Point(10, 12), Point(10, 22), 1)); data.push_back(vertex_half_edge(Point(10, 22), Point(10, 12), -1)); data.push_back(vertex_half_edge(Point(10, 22), Point(2, 22), -1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } //pf2.scan(polys2, data.begin(), data.end()); //stdcout << "result size: " << polys2.size() << "\n"; //for(std::size_t i = 0; i < polys2.size(); ++i) { // stdcout << polys2[i] << "\n"; //} stdcout << "done testing trapezoid formation\n"; return true; } template <typename stream_type> static inline bool testTrapezoidArbitraryFormationSelfTouch1(stream_type& stdcout) { stdcout << "testing trapezoid formation self touch 1\n"; trapezoid_arbitrary_formation pf; std::vector<polygon_data<Unit> > polys; std::vector<vertex_half_edge> data; data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(0, 10), Point(5, 10), -1)); data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); data.push_back(vertex_half_edge(Point(10, 0), Point(10, 5), -1)); data.push_back(vertex_half_edge(Point(10, 5), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(10, 5), Point(5, 5), 1)); data.push_back(vertex_half_edge(Point(5, 10), Point(5, 5), 1)); data.push_back(vertex_half_edge(Point(5, 10), Point(0, 10), 1)); data.push_back(vertex_half_edge(Point(5, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(5, 2), Point(7, 2), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(5, 10), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(5, 2), 1)); data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(7, 2), Point(5, 2), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } stdcout << "done testing trapezoid formation\n"; return true; } }; template <typename T> struct PolyLineArbitraryByConcept<T, polygon_with_holes_concept> { typedef poly_line_arbitrary_polygon_data<T> type; }; template <typename T> struct PolyLineArbitraryByConcept<T, polygon_concept> { typedef poly_line_arbitrary_hole_data<T> type; }; template <typename T> struct geometry_concept<poly_line_arbitrary_polygon_data<T> > { typedef polygon_45_with_holes_concept type; }; template <typename T> struct geometry_concept<poly_line_arbitrary_hole_data<T> > { typedef polygon_45_concept type; }; } } #endif detail/scan_arbitrary.hpp 0000644 00000433035 15125572616 0011544 0 ustar 00 /* 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_SCAN_ARBITRARY_HPP #define BOOST_POLYGON_SCAN_ARBITRARY_HPP #ifdef BOOST_POLYGON_DEBUG_FILE #include <fstream> #endif #include "polygon_sort_adaptor.hpp" namespace boost { namespace polygon{ template <typename Unit> class line_intersection : public scanline_base<Unit> { private: typedef typename scanline_base<Unit>::Point Point; //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex //typedef std::pair<Point, Point> half_edge; typedef typename scanline_base<Unit>::half_edge half_edge; //scanline comparator functor typedef typename scanline_base<Unit>::less_half_edge less_half_edge; typedef typename scanline_base<Unit>::less_point less_point; //when parallel half edges are encounterd the set of segments is expanded //when a edge leaves the scanline it is removed from the set //when the set is empty the element is removed from the map typedef int segment_id; typedef std::pair<half_edge, std::set<segment_id> > scanline_element; typedef std::map<half_edge, std::set<segment_id>, less_half_edge> edge_scanline; typedef typename edge_scanline::iterator iterator; // std::map<Unit, std::set<segment_id> > vertical_data_; // edge_scanline edge_scanline_; // Unit x_; // int just_before_; // segment_id segment_id_; // std::vector<std::pair<half_edge, int> > event_edges_; // std::set<Point> intersection_queue_; public: // inline line_intersection() : vertical_data_(), edge_scanline_(), x_((std::numeric_limits<Unit>::max)()), just_before_(0), segment_id_(0), event_edges_(), intersection_queue_() { // less_half_edge lessElm(&x_, &just_before_); // edge_scanline_ = edge_scanline(lessElm); // } // inline line_intersection(const line_intersection& that) : vertical_data_(), edge_scanline_(), x_(), just_before_(), segment_id_(), event_edges_(), intersection_queue_() { (*this) = that; } // inline line_intersection& operator=(const line_intersection& that) { // x_ = that.x_; // just_before_ = that.just_before_; // segment_id_ = that.segment_id_; // //I cannot simply copy that.edge_scanline_ to this edge_scanline_ becuase the functor store pointers to other members! // less_half_edge lessElm(&x_, &just_before_); // edge_scanline_ = edge_scanline(lessElm); // edge_scanline_.insert(that.edge_scanline_.begin(), that.edge_scanline_.end()); // return *this; // } // static inline void between(Point pt, Point pt1, Point pt2) { // less_point lp; // if(lp(pt1, pt2)) // return lp(pt, pt2) && lp(pt1, pt); // return lp(pt, pt1) && lp(pt2, pt); // } template <typename iT> static inline void compute_histogram_in_y(iT begin, iT end, std::size_t size, std::vector<std::pair<Unit, std::pair<std::size_t, std::size_t> > >& histogram) { std::vector<std::pair<Unit, int> > ends; ends.reserve(size * 2); for(iT itr = begin ; itr != end; ++itr) { int count = (*itr).first.first.y() < (*itr).first.second.y() ? 1 : -1; ends.push_back(std::make_pair((*itr).first.first.y(), count)); ends.push_back(std::make_pair((*itr).first.second.y(), -count)); } polygon_sort(ends.begin(), ends.end()); histogram.reserve(ends.size()); histogram.push_back(std::make_pair(ends.front().first, std::make_pair(0, 0))); for(typename std::vector<std::pair<Unit, int> >::iterator itr = ends.begin(); itr != ends.end(); ++itr) { if((*itr).first != histogram.back().first) { histogram.push_back(std::make_pair((*itr).first, histogram.back().second)); } if((*itr).second < 0) histogram.back().second.second -= (*itr).second; histogram.back().second.first += (*itr).second; } } template <typename iT> static inline void compute_y_cuts(std::vector<Unit>& y_cuts, iT begin, iT end, std::size_t size) { if(begin == end) return; if(size < 30) return; //30 is empirically chosen, but the algorithm is not sensitive to this constant std::size_t min_cut = size; iT cut = begin; std::size_t position = 0; std::size_t cut_size = 0; std::size_t histogram_size = std::distance(begin, end); for(iT itr = begin; itr != end; ++itr, ++position) { if(position < histogram_size / 3) continue; if(histogram_size - position < histogram_size / 3) break; if((*itr).second.first < min_cut) { cut = itr; min_cut = (*cut).second.first; cut_size = position; } } if(cut_size == 0 || (*cut).second.first > size / 9) //nine is empirically chosen return; compute_y_cuts(y_cuts, begin, cut, (*cut).second.first + (*cut).second.second); y_cuts.push_back((*cut).first); compute_y_cuts(y_cuts, cut, end, size - (*cut).second.second); } template <typename iT> static inline void validate_scan_divide_and_conquer(std::vector<std::set<Point> >& intersection_points, iT begin, iT end) { std::vector<std::pair<Unit, std::pair<std::size_t, std::size_t> > > histogram; compute_histogram_in_y(begin, end, std::distance(begin, end), histogram); std::vector<Unit> y_cuts; compute_y_cuts(y_cuts, histogram.begin(), histogram.end(), std::distance(begin, end)); std::map<Unit, std::vector<std::pair<half_edge, segment_id> > > bins; bins[histogram.front().first] = std::vector<std::pair<half_edge, segment_id> >(); for(typename std::vector<Unit>::iterator itr = y_cuts.begin(); itr != y_cuts.end(); ++itr) { bins[*itr] = std::vector<std::pair<half_edge, segment_id> >(); } for(iT itr = begin; itr != end; ++itr) { typename std::map<Unit, std::vector<std::pair<half_edge, segment_id> > >::iterator lb = bins.lower_bound((std::min)((*itr).first.first.y(), (*itr).first.second.y())); if(lb != bins.begin()) --lb; typename std::map<Unit, std::vector<std::pair<half_edge, segment_id> > >::iterator ub = bins.upper_bound((std::max)((*itr).first.first.y(), (*itr).first.second.y())); for( ; lb != ub; ++lb) { (*lb).second.push_back(*itr); } } validate_scan(intersection_points, bins[histogram.front().first].begin(), bins[histogram.front().first].end()); for(typename std::vector<Unit>::iterator itr = y_cuts.begin(); itr != y_cuts.end(); ++itr) { validate_scan(intersection_points, bins[*itr].begin(), bins[*itr].end(), *itr); } } template <typename iT> static inline void validate_scan(std::vector<std::set<Point> >& intersection_points, iT begin, iT end) { validate_scan(intersection_points, begin, end, (std::numeric_limits<Unit>::min)()); } //quadratic algorithm to do same work as optimal scan for cross checking template <typename iT> static inline void validate_scan(std::vector<std::set<Point> >& intersection_points, iT begin, iT end, Unit min_y) { std::vector<Point> pts; std::vector<std::pair<half_edge, segment_id> > data(begin, end); for(std::size_t i = 0; i < data.size(); ++i) { if(data[i].first.second < data[i].first.first) { std::swap(data[i].first.first, data[i].first.second); } } typename scanline_base<Unit>::compute_intersection_pack pack_; polygon_sort(data.begin(), data.end()); //find all intersection points for(typename std::vector<std::pair<half_edge, segment_id> >::iterator outer = data.begin(); outer != data.end(); ++outer) { const half_edge& he1 = (*outer).first; //its own end points pts.push_back(he1.first); pts.push_back(he1.second); std::set<Point>& segmentpts = intersection_points[(*outer).second]; for(typename std::set<Point>::iterator itr = segmentpts.begin(); itr != segmentpts.end(); ++itr) { if ((*itr).y() >= min_y) { pts.push_back(*itr); } } bool have_first_y = he1.first.y() >= min_y && he1.second.y() >= min_y; for(typename std::vector<std::pair<half_edge, segment_id> >::iterator inner = outer; inner != data.end(); ++inner) { const half_edge& he2 = (*inner).first; if(have_first_y || (he2.first.y() >= min_y && he2.second.y() >= min_y)) { //at least one segment has a low y value within the range if(he1 == he2) continue; if((std::min)(he2. first.get(HORIZONTAL), he2.second.get(HORIZONTAL)) >= (std::max)(he1.second.get(HORIZONTAL), he1.first.get(HORIZONTAL))) break; if(he1.first == he2.first || he1.second == he2.second) continue; Point intersection; if(pack_.compute_intersection(intersection, he1, he2)) { //their intersection point pts.push_back(intersection); intersection_points[(*inner).second].insert(intersection); intersection_points[(*outer).second].insert(intersection); } } } } polygon_sort(pts.begin(), pts.end()); typename std::vector<Point>::iterator newend = std::unique(pts.begin(), pts.end()); typename std::vector<Point>::iterator lfinger = pts.begin(); //find all segments that interact with intersection points for(typename std::vector<std::pair<half_edge, segment_id> >::iterator outer = data.begin(); outer != data.end(); ++outer) { const half_edge& he1 = (*outer).first; segment_id id1 = (*outer).second; //typedef rectangle_data<Unit> Rectangle; //Rectangle rect1; //set_points(rect1, he1.first, he1.second); //typename std::vector<Point>::iterator itr = lower_bound(pts.begin(), newend, (std::min)(he1.first, he1.second)); //typename std::vector<Point>::iterator itr2 = upper_bound(pts.begin(), newend, (std::max)(he1.first, he1.second)); Point startpt = (std::min)(he1.first, he1.second); Point stoppt = (std::max)(he1.first, he1.second); //while(itr != newend && itr != pts.begin() && (*itr).get(HORIZONTAL) >= (std::min)(he1.first.get(HORIZONTAL), he1.second.get(HORIZONTAL))) --itr; //while(itr2 != newend && (*itr2).get(HORIZONTAL) <= (std::max)(he1.first.get(HORIZONTAL), he1.second.get(HORIZONTAL))) ++itr2; //itr = pts.begin(); //itr2 = pts.end(); while(lfinger != newend && (*lfinger).x() < startpt.x()) ++lfinger; for(typename std::vector<Point>::iterator itr = lfinger ; itr != newend && (*itr).x() <= stoppt.x(); ++itr) { if(scanline_base<Unit>::intersects_grid(*itr, he1)) intersection_points[id1].insert(*itr); } } } template <typename iT, typename property_type> static inline void validate_scan(std::vector<std::pair<half_edge, std::pair<property_type, int> > >& output_segments, iT begin, iT end) { std::vector<std::pair<property_type, int> > input_properties; std::vector<std::pair<half_edge, int> > input_segments, intermediate_segments; int index = 0; for( ; begin != end; ++begin) { input_properties.push_back((*begin).second); input_segments.push_back(std::make_pair((*begin).first, index++)); } validate_scan(intermediate_segments, input_segments.begin(), input_segments.end()); for(std::size_t i = 0; i < intermediate_segments.size(); ++i) { output_segments.push_back(std::make_pair(intermediate_segments[i].first, input_properties[intermediate_segments[i].second])); less_point lp; if(lp(output_segments.back().first.first, output_segments.back().first.second) != lp(input_segments[intermediate_segments[i].second].first.first, input_segments[intermediate_segments[i].second].first.second)) { //edge changed orientation, invert count on edge output_segments.back().second.second *= -1; } if(!scanline_base<Unit>::is_vertical(input_segments[intermediate_segments[i].second].first) && scanline_base<Unit>::is_vertical(output_segments.back().first)) { output_segments.back().second.second *= -1; } if(lp(output_segments.back().first.second, output_segments.back().first.first)) { std::swap(output_segments.back().first.first, output_segments.back().first.second); } } } template <typename iT> static inline void validate_scan(std::vector<std::pair<half_edge, int> >& output_segments, iT begin, iT end) { std::vector<std::set<Point> > intersection_points(std::distance(begin, end)); validate_scan_divide_and_conquer(intersection_points, begin, end); //validate_scan(intersection_points, begin, end); segment_intersections(output_segments, intersection_points, begin, end); // std::pair<segment_id, segment_id> offenders; // if(!verify_scan(offenders, output_segments.begin(), output_segments.end())) { // std::cout << "break here!\n"; // for(typename std::set<Point>::iterator itr = intersection_points[offenders.first].begin(); // itr != intersection_points[offenders.first].end(); ++itr) { // std::cout << (*itr).x() << " " << (*itr).y() << " "; // } std::cout << "\n"; // for(typename std::set<Point>::iterator itr = intersection_points[offenders.second].begin(); // itr != intersection_points[offenders.second].end(); ++itr) { // std::cout << (*itr).x() << " " << (*itr).y() << " "; // } std::cout << "\n"; // exit(1); // } } //quadratic algorithm to find intersections template <typename iT, typename segment_id> static inline bool verify_scan(std::pair<segment_id, segment_id>& offenders, iT begin, iT end) { std::vector<std::pair<half_edge, segment_id> > data(begin, end); for(std::size_t i = 0; i < data.size(); ++i) { if(data[i].first.second < data[i].first.first) { std::swap(data[i].first.first, data[i].first.second); } } polygon_sort(data.begin(), data.end()); for(typename std::vector<std::pair<half_edge, segment_id> >::iterator outer = data.begin(); outer != data.end(); ++outer) { const half_edge& he1 = (*outer).first; segment_id id1 = (*outer).second; for(typename std::vector<std::pair<half_edge, segment_id> >::iterator inner = outer; inner != data.end(); ++inner) { const half_edge& he2 = (*inner).first; if(he1 == he2) continue; if((std::min)(he2. first.get(HORIZONTAL), he2.second.get(HORIZONTAL)) > (std::max)(he1.second.get(HORIZONTAL), he1.first.get(HORIZONTAL))) break; segment_id id2 = (*inner).second; if(scanline_base<Unit>::intersects(he1, he2)) { offenders.first = id1; offenders.second = id2; //std::cout << he1.first.x() << " " << he1.first.y() << " " << he1.second.x() << " " << he1.second.y() << " " << he2.first.x() << " " << he2.first.y() << " " << he2.second.x() << " " << he2.second.y() << "\n"; return false; } } } return true; } class less_point_down_slope { public: typedef Point first_argument_type; typedef Point second_argument_type; typedef bool result_type; inline less_point_down_slope() {} inline bool operator () (const Point& pt1, const Point& pt2) const { if(pt1.get(HORIZONTAL) < pt2.get(HORIZONTAL)) return true; if(pt1.get(HORIZONTAL) == pt2.get(HORIZONTAL)) { if(pt1.get(VERTICAL) > pt2.get(VERTICAL)) return true; } return false; } }; template <typename iT> static inline void segment_edge(std::vector<std::pair<half_edge, int> >& output_segments, const half_edge& , segment_id id, iT begin, iT end) { iT current = begin; iT next = begin; ++next; while(next != end) { output_segments.push_back(std::make_pair(half_edge(*current, *next), id)); current = next; ++next; } } template <typename iT> static inline void segment_intersections(std::vector<std::pair<half_edge, int> >& output_segments, std::vector<std::set<Point> >& intersection_points, iT begin, iT end) { for(iT iter = begin; iter != end; ++iter) { //less_point lp; const half_edge& he = (*iter).first; //if(lp(he.first, he.second)) { // //it is the begin event segment_id id = (*iter).second; const std::set<Point>& pts = intersection_points[id]; Point hpt(he.first.get(HORIZONTAL)+1, he.first.get(VERTICAL)); if(!scanline_base<Unit>::is_vertical(he) && scanline_base<Unit>::less_slope(he.first.get(HORIZONTAL), he.first.get(VERTICAL), he.second, hpt)) { //slope is below horizontal std::vector<Point> tmpPts; tmpPts.reserve(pts.size()); tmpPts.insert(tmpPts.end(), pts.begin(), pts.end()); less_point_down_slope lpds; polygon_sort(tmpPts.begin(), tmpPts.end(), lpds); segment_edge(output_segments, he, id, tmpPts.begin(), tmpPts.end()); } else { segment_edge(output_segments, he, id, pts.begin(), pts.end()); } //} } } // //iT iterator over unsorted pair<Point> representing line segments of input // //output_segments is populated with fully intersected output line segment half // //edges and the index of the input segment that they are assoicated with // //duplicate output half edges with different ids will be generated in the case // //that parallel input segments intersection // //outputs are in sorted order and include both begin and end events for // //each segment // template <typename iT> // inline void scan(std::vector<std::pair<half_edge, int> >& output_segments, // iT begin, iT end) { // std::map<segment_id, std::set<Point> > intersection_points; // scan(intersection_points, begin, end); // segment_intersections(output_segments, intersection_points, begin, end); // } // //iT iterator over sorted sequence of half edge, segment id pairs representing segment begin and end points // //intersection points provides a mapping from input segment id (vector index) to the set // //of intersection points assocated with that input segment // template <typename iT> // inline void scan(std::map<segment_id, std::set<Point> >& intersection_points, // iT begin, iT end) { // for(iT iter = begin; iter != end; ++iter) { // const std::pair<half_edge, int>& elem = *iter; // const half_edge& he = elem.first; // Unit current_x = he.first.get(HORIZONTAL); // if(current_x != x_) { // process_scan_event(intersection_points); // while(!intersection_queue_.empty() && // (*(intersection_queue_.begin()).get(HORIZONTAL) < current_x)) { // x_ = *(intersection_queue_.begin()).get(HORIZONTAL); // process_intersections_at_scan_event(intersection_points); // } // x_ = current_x; // } // event_edges_.push_back(elem); // } // process_scan_event(intersection_points); // } // inline iterator lookup(const half_edge& he) { // return edge_scanline_.find(he); // } // inline void insert_into_scanline(const half_edge& he, int id) { // edge_scanline_[he].insert(id); // } // inline void lookup_and_remove(const half_edge& he, int id) { // iterator remove_iter = lookup(he); // if(remove_iter == edge_scanline_.end()) { // //std::cout << "failed to find removal segment in scanline\n"; // return; // } // std::set<segment_id>& ids = (*remove_iter).second; // std::set<segment_id>::iterator id_iter = ids.find(id); // if(id_iter == ids.end()) { // //std::cout << "failed to find removal segment id in scanline set\n"; // return; // } // ids.erase(id_iter); // if(ids.empty()) // edge_scanline_.erase(remove_iter); // } // static inline void update_segments(std::map<segment_id, std::set<Point> >& intersection_points, // const std::set<segment_id>& segments, Point pt) { // for(std::set<segment_id>::const_iterator itr = segments.begin(); itr != segments.end(); ++itr) { // intersection_points[*itr].insert(pt); // } // } // inline void process_intersections_at_scan_event(std::map<segment_id, std::set<Point> >& intersection_points) { // //there may be additional intersection points at this x location that haven't been // //found yet if vertical or near vertical line segments intersect more than // //once before the next x location // just_before_ = true; // std::set<iterator> intersecting_elements; // std::set<Unit> intersection_locations; // typedef typename std::set<Point>::iterator intersection_iterator; // intersection_iterator iter; // //first find all secondary intersection locations and all scanline iterators // //that are intersecting // for(iter = intersection_queue_.begin(); // iter != intersection_queue_.end() && (*iter).get(HORIZONTAL) == x_; ++iter) { // Point pt = *iter; // Unit y = pt.get(VERTICAL); // intersection_locations.insert(y); // //if x_ is max there can be only end events and no sloping edges // if(x_ != (std::numeric_limits<Unit>::max)()) { // //deal with edges that project to the right of scanline // //first find the edges in the scanline adjacent to primary intersectin points // //lookup segment in scanline at pt // iterator itr = edge_scanline_.lower_bound(half_edge(pt, Point(x_+1, y))); // //look above pt in scanline until reaching end or segment that doesn't intersect // //1x1 grid upper right of pt // //look below pt in scanline until reaching begin or segment that doesn't interset // //1x1 grid upper right of pt // //second find edges in scanline on the y interval of each edge found in the previous // //step for x_ to x_ + 1 // //third find overlaps in the y intervals of all found edges to find all // //secondary intersection points // } // } // //erase the intersection points from the queue // intersection_queue_.erase(intersection_queue_.begin(), iter); // std::vector<scanline_element> insertion_edges; // insertion_edges.reserve(intersecting_elements.size()); // std::vector<std::pair<Unit, iterator> > sloping_ends; // //do all the work of updating the output of all intersecting // for(typename std::set<iterator>::iterator inter_iter = intersecting_elements.begin(); // inter_iter != intersecting_elements.end(); ++inter_iter) { // //if it is horizontal update it now and continue // if(is_horizontal((*inter_iter).first)) { // update_segments(intersection_points, (*inter_iter).second, Point(x_, (*inter_iter).first.get(VERTICAL))); // } else { // //if x_ is max there can be only end events and no sloping edges // if(x_ != (std::numeric_limits<Unit>::max)()) { // //insert its end points into the vector of sloping ends // const half_edge& he = (*inter_iter).first; // Unit y = evalAtXforY(x_, he.first, he.second); // Unit y2 = evalAtXforY(x_+1, he.first, he.second); // if(y2 >= y) y2 +=1; //we round up, in exact case we don't worry about overbite of one // else y += 1; //downward sloping round up // sloping_ends.push_back(std::make_pair(y, inter_iter)); // sloping_ends.push_back(std::make_pair(y2, inter_iter)); // } // } // } // //merge sloping element data // polygon_sort(sloping_ends.begin(), sloping_ends.end()); // std::map<Unit, std::set<iterator> > sloping_elements; // std::set<iterator> merge_elements; // for(typename std::vector<std::pair<Unit, iterator> >::iterator slop_iter = sloping_ends.begin(); // slop_iter == sloping_ends.end(); ++slop_iter) { // //merge into sloping elements // typename std::set<iterator>::iterator merge_iterator = merge_elements.find((*slop_iter).second); // if(merge_iterator == merge_elements.end()) { // merge_elements.insert((*slop_iter).second); // } else { // merge_elements.erase(merge_iterator); // } // sloping_elements[(*slop_iter).first] = merge_elements; // } // //scan intersection points // typename std::map<Unit, std::set<segment_id> >::iterator vertical_iter = vertical_data_.begin(); // typename std::map<Unit, std::set<iterator> >::iterator sloping_iter = sloping_elements.begin(); // for(typename std::set<Unit>::iterator position_iter = intersection_locations.begin(); // position_iter == intersection_locations.end(); ++position_iter) { // //look for vertical segments that intersect this point and update them // Unit y = *position_iter; // Point pt(x_, y); // //handle vertical segments // if(vertical_iter != vertical_data_.end()) { // typename std::map<Unit, std::set<segment_id> >::iterator next_vertical = vertical_iter; // for(++next_vertical; next_vertical != vertical_data_.end() && // (*next_vertical).first < y; ++next_vertical) { // vertical_iter = next_vertical; // } // if((*vertical_iter).first < y && !(*vertical_iter).second.empty()) { // update_segments(intersection_points, (*vertical_iter).second, pt); // ++vertical_iter; // if(vertical_iter != vertical_data_.end() && (*vertical_iter).first == y) // update_segments(intersection_points, (*vertical_iter).second, pt); // } // } // //handle sloping segments // if(sloping_iter != sloping_elements.end()) { // typename std::map<Unit, std::set<iterator> >::iterator next_sloping = sloping_iter; // for(++next_sloping; next_sloping != sloping_elements.end() && // (*next_sloping).first < y; ++next_sloping) { // sloping_iter = next_sloping; // } // if((*sloping_iter).first < y && !(*sloping_iter).second.empty()) { // for(typename std::set<iterator>::iterator element_iter = (*sloping_iter).second.begin(); // element_iter != (*sloping_iter).second.end(); ++element_iter) { // const half_edge& he = (*element_iter).first; // if(intersects_grid(pt, he)) { // update_segments(intersection_points, (*element_iter).second, pt); // } // } // ++sloping_iter; // if(sloping_iter != sloping_elements.end() && (*sloping_iter).first == y && // !(*sloping_iter).second.empty()) { // for(typename std::set<iterator>::iterator element_iter = (*sloping_iter).second.begin(); // element_iter != (*sloping_iter).second.end(); ++element_iter) { // const half_edge& he = (*element_iter).first; // if(intersects_grid(pt, he)) { // update_segments(intersection_points, (*element_iter).second, pt); // } // } // } // } // } // } // //erase and reinsert edges into scanline with check for future intersection // } // inline void process_scan_event(std::map<segment_id, std::set<Point> >& intersection_points) { // just_before_ = true; // //process end events by removing those segments from the scanline // //and insert vertices of all events into intersection queue // Point prev_point((std::numeric_limits<Unit>::min)(), (std::numeric_limits<Unit>::min)()); // less_point lp; // std::set<segment_id> vertical_ids; // vertical_data_.clear(); // for(std::size_t i = 0; i < event_edges_.size(); ++i) { // segment_id id = event_edges_[i].second; // const half_edge& he = event_edges_[i].first; // //vertical half edges are handled during intersection processing because // //they cannot be inserted into the scanline // if(!is_vertical(he)) { // if(lp(he.second, he.first)) { // //half edge is end event // lookup_and_remove(he, id); // } else { // //half edge is begin event // insert_into_scanline(he, id); // //note that they will be immediately removed and reinserted after // //handling their intersection (vertex) // //an optimization would allow them to be processed specially to avoid the redundant // //removal and reinsertion // } // } else { // //common case if you are lucky // //update the map of y to set of segment id // if(lp(he.second, he.first)) { // //half edge is end event // std::set<segment_id>::iterator itr = vertical_ids.find(id); // if(itr == vertical_ids.end()) { // //std::cout << "Failed to find end event id in vertical ids\n"; // } else { // vertical_ids.erase(itr); // vertical_data_[he.first.get(HORIZONTAL)] = vertical_ids; // } // } else { // //half edge is a begin event // vertical_ids.insert(id); // vertical_data_[he.first.get(HORIZONTAL)] = vertical_ids; // } // } // //prevent repeated insertion of same vertex into intersection queue // if(prev_point != he.first) // intersection_queue_.insert(he.first); // else // prev_point = he.first; // // process intersections at scan event // process_intersections_at_scan_event(intersection_points); // } // event_edges_.clear(); // } public: template <typename stream_type> static inline bool test_validate_scan(stream_type& stdcout) { std::vector<std::pair<half_edge, segment_id> > input, edges; input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), 0)); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 10)), 1)); std::pair<segment_id, segment_id> result; validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail1 " << result.first << " " << result.second << "\n"; return false; } input.push_back(std::make_pair(half_edge(Point(0, 5), Point(5, 5)), 2)); edges.clear(); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail2 " << result.first << " " << result.second << "\n"; return false; } input.pop_back(); input.push_back(std::make_pair(half_edge(Point(1, 0), Point(11, 11)), input.size())); edges.clear(); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail3 " << result.first << " " << result.second << "\n"; return false; } input.push_back(std::make_pair(half_edge(Point(1, 0), Point(10, 11)), input.size())); edges.clear(); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail4 " << result.first << " " << result.second << "\n"; return false; } input.pop_back(); input.push_back(std::make_pair(half_edge(Point(1, 2), Point(11, 11)), input.size())); edges.clear(); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail5 " << result.first << " " << result.second << "\n"; return false; } input.push_back(std::make_pair(half_edge(Point(0, 5), Point(0, 11)), input.size())); edges.clear(); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail6 " << result.first << " " << result.second << "\n"; return false; } input.pop_back(); for(std::size_t i = 0; i < input.size(); ++i) { std::swap(input[i].first.first, input[i].first.second); } edges.clear(); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail5 2 " << result.first << " " << result.second << "\n"; return false; } for(std::size_t i = 0; i < input.size(); ++i) { input[i].first.first = Point(input[i].first.first.get(HORIZONTAL) * -1, input[i].first.first.get(VERTICAL) * -1); input[i].first.second = Point(input[i].first.second.get(HORIZONTAL) * -1, input[i].first.second.get(VERTICAL) * -1); } edges.clear(); validate_scan(edges, input.begin(), input.end()); stdcout << edges.size() << "\n"; if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail5 3 " << result.first << " " << result.second << "\n"; return false; } input.clear(); edges.clear(); input.push_back(std::make_pair(half_edge(Point(5, 7), Point(7, 6)), 0)); input.push_back(std::make_pair(half_edge(Point(2, 4), Point(6, 7)), 1)); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail2 1 " << result.first << " " << result.second << "\n"; print(input); print(edges); return false; } input.clear(); edges.clear(); input.push_back(std::make_pair(half_edge(Point(3, 2), Point(1, 7)), 0)); input.push_back(std::make_pair(half_edge(Point(0, 6), Point(7, 4)), 1)); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail2 2 " << result.first << " " << result.second << "\n"; print(input); print(edges); return false; } input.clear(); edges.clear(); input.push_back(std::make_pair(half_edge(Point(6, 6), Point(1, 0)), 0)); input.push_back(std::make_pair(half_edge(Point(3, 6), Point(2, 3)), 1)); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail2 3 " << result.first << " " << result.second << "\n"; print(input); print(edges); return false; } input.clear(); edges.clear(); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(7, 0)), 0)); input.push_back(std::make_pair(half_edge(Point(6, 0), Point(2, 0)), 1)); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail2 4 " << result.first << " " << result.second << "\n"; print(input); print(edges); return false; } input.clear(); edges.clear(); input.push_back(std::make_pair(half_edge(Point(-17333131 - -17208131, -10316869 - -10191869), Point(0, 0)), 0)); input.push_back(std::make_pair(half_edge(Point(-17291260 - -17208131, -10200000 - -10191869), Point(-17075000 - -17208131, -10200000 - -10191869)), 1)); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail2 5 " << result.first << " " << result.second << "\n"; print(input); print(edges); return false; } input.clear(); edges.clear(); input.push_back(std::make_pair(half_edge(Point(-17333131, -10316869), Point(-17208131, -10191869)), 0)); input.push_back(std::make_pair(half_edge(Point(-17291260, -10200000), Point(-17075000, -10200000)), 1)); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail2 6 " << result.first << " " << result.second << "\n"; print(input); print(edges); return false; } input.clear(); edges.clear(); input.push_back(std::make_pair(half_edge(Point(-9850009+9853379, -286971+290340), Point(-12777869+9853379, -3214831+290340)), 0)); input.push_back(std::make_pair(half_edge(Point(-5223510+9853379, -290340+290340), Point(-9858140+9853379, -290340+290340)), 1)); validate_scan(edges, input.begin(), input.end()); print(edges); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail2 7 " << result.first << " " << result.second << "\n"; print(input); print(edges); return false; } input.clear(); edges.clear(); input.push_back(std::make_pair(half_edge(Point(-9850009, -286971), Point(-12777869, -3214831)), 0)); input.push_back(std::make_pair(half_edge(Point(-5223510, -290340), Point(-9858140, -290340)), 1)); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail2 8 " << result.first << " " << result.second << "\n"; print(input); print(edges); return false; } //3 3 2 2: 0; 4 2 0 6: 1; 0 3 6 3: 2; 4 1 5 5: 3; input.clear(); edges.clear(); input.push_back(std::make_pair(half_edge(Point(3, 3), Point(2, 2)), 0)); input.push_back(std::make_pair(half_edge(Point(4, 2), Point(0, 6)), 1)); input.push_back(std::make_pair(half_edge(Point(0, 3), Point(6, 3)), 2)); input.push_back(std::make_pair(half_edge(Point(4, 1), Point(5, 5)), 3)); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail4 1 " << result.first << " " << result.second << "\n"; print(input); print(edges); return false; } //5 7 1 3: 0; 4 5 2 1: 1; 2 5 2 1: 2; 4 1 5 3: 3; input.clear(); edges.clear(); input.push_back(std::make_pair(half_edge(Point(5, 7), Point(1, 3)), 0)); input.push_back(std::make_pair(half_edge(Point(4, 5), Point(2, 1)), 1)); input.push_back(std::make_pair(half_edge(Point(2, 5), Point(2, 1)), 2)); input.push_back(std::make_pair(half_edge(Point(4, 1), Point(5, 3)), 3)); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail4 2 " << result.first << " " << result.second << "\n"; print(input); print(edges); return false; } //1 0 -4 -1: 0; 0 0 2 -1: 1; input.clear(); edges.clear(); input.push_back(std::make_pair(half_edge(Point(1, 0), Point(-4, -1)), 0)); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(2, -1)), 1)); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail2 5 " << result.first << " " << result.second << "\n"; print(input); print(edges); return false; } Unit min_c =0; Unit max_c =0; for(unsigned int outer = 0; outer < 1000; ++outer) { input.clear(); for(unsigned int i = 0; i < 4; ++i) { Unit x1 = rand(); Unit x2 = rand(); Unit y1 = rand(); Unit y2 = rand(); int neg1 = rand() % 2; if(neg1) x1 *= -1; int neg2 = rand() % 2; if(neg2) x2 *= -1; int neg3 = rand() % 2; if(neg3) y1 *= -1; int neg4 = rand() % 2; if(neg4) y2 *= -1; if(x1 < min_c) min_c = x1; if(x2 < min_c) min_c = x2; if(y1 < min_c) min_c = y1; if(y2 < min_c) min_c = y2; if(x1 > max_c) max_c = x1; if(x2 > max_c) max_c = x2; if(y1 > max_c) max_c = y1; if(y2 > max_c) max_c = y2; Point pt1(x1, y1); Point pt2(x2, y2); if(pt1 != pt2) input.push_back(std::make_pair(half_edge(pt1, pt2), i)); } edges.clear(); validate_scan(edges, input.begin(), input.end()); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail9 " << outer << ": " << result.first << " " << result.second << "\n"; print(input); print(edges); return false; } } return true; } //static void print(const std::pair<half_edge, segment_id>& segment) { //std::cout << segment.first.first << " " << segment.first.second << ": " << segment.second << "; "; //} static void print(const std::vector<std::pair<half_edge, segment_id> >& vec) { for(std::size_t i = 0; i < vec.size(); ++ i) { // print(vec[i]); } //std::cout << "\n"; } template <typename stream_type> static inline bool test_verify_scan(stream_type& stdcout) { std::vector<std::pair<half_edge, segment_id> > edges; edges.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), 0)); edges.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 10)), 1)); std::pair<segment_id, segment_id> result; if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "fail1\n"; return false; } edges.push_back(std::make_pair(half_edge(Point(0, 5), Point(5, 5)), 2)); if(verify_scan(result, edges.begin(), edges.end())) { stdcout << "fail2\n"; return false; } edges.pop_back(); edges.push_back(std::make_pair(half_edge(Point(1, 0), Point(11, 11)), (segment_id)edges.size())); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "fail3\n"; return false; } edges.push_back(std::make_pair(half_edge(Point(1, 0), Point(10, 11)), (segment_id)edges.size())); if(verify_scan(result, edges.begin(), edges.end())) { stdcout << "fail4\n"; return false; } edges.pop_back(); edges.push_back(std::make_pair(half_edge(Point(1, 2), Point(11, 11)), (segment_id)edges.size())); if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "fail5 " << result.first << " " << result.second << "\n"; return false; } edges.push_back(std::make_pair(half_edge(Point(0, 5), Point(0, 11)), (segment_id)edges.size())); if(verify_scan(result, edges.begin(), edges.end())) { stdcout << "fail6 " << result.first << " " << result.second << "\n"; return false; } edges.pop_back(); for(std::size_t i = 0; i < edges.size(); ++i) { std::swap(edges[i].first.first, edges[i].first.second); } if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "fail5 2 " << result.first << " " << result.second << "\n"; return false; } for(std::size_t i = 0; i < edges.size(); ++i) { edges[i].first.first = Point(edges[i].first.first.get(HORIZONTAL) * -1, edges[i].first.first.get(VERTICAL) * -1); edges[i].first.second = Point(edges[i].first.second.get(HORIZONTAL) * -1, edges[i].first.second.get(VERTICAL) * -1); } if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "fail5 3 " << result.first << " " << result.second << "\n"; return false; } return true; } }; //scanline consumes the "flattened" fully intersected line segments produced by //a pass of line_intersection along with property and count information and performs a //useful operation like booleans or property merge or connectivity extraction template <typename Unit, typename property_type, typename keytype = std::set<property_type> > class scanline : public scanline_base<Unit> { public: //definitions typedef typename scanline_base<Unit>::Point Point; //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex //typedef std::pair<Point, Point> half_edge; typedef typename scanline_base<Unit>::half_edge half_edge; //scanline comparator functor typedef typename scanline_base<Unit>::less_half_edge less_half_edge; typedef typename scanline_base<Unit>::less_point less_point; typedef keytype property_set; //this is the data type used internally to store the combination of property counts at a given location typedef std::vector<std::pair<property_type, int> > property_map; //this data structure assocates a property and count to a half edge typedef std::pair<half_edge, std::pair<property_type, int> > vertex_property; //this data type is used internally to store the combined property data for a given half edge typedef std::pair<half_edge, property_map> vertex_data; //this data type stores the combination of many half edges typedef std::vector<vertex_property> property_merge_data; //this data structure stores end points of edges in the scanline typedef std::set<Point, less_point> end_point_queue; //this is the output data type that is created by the scanline before it is post processed based on content of property sets typedef std::pair<half_edge, std::pair<property_set, property_set> > half_edge_property; //this is the scanline data structure typedef std::map<half_edge, property_map, less_half_edge> scanline_type; typedef std::pair<half_edge, property_map> scanline_element; typedef typename scanline_type::iterator iterator; typedef typename scanline_type::const_iterator const_iterator; //data scanline_type scan_data_; std::vector<iterator> removal_set_; //edges to be removed at the current scanline stop std::vector<scanline_element> insertion_set_; //edge to be inserted after current scanline stop end_point_queue end_point_queue_; Unit x_; Unit y_; int just_before_; typename scanline_base<Unit>::evalAtXforYPack evalAtXforYPack_; public: inline scanline() : scan_data_(), removal_set_(), insertion_set_(), end_point_queue_(), x_((std::numeric_limits<Unit>::max)()), y_((std::numeric_limits<Unit>::max)()), just_before_(false), evalAtXforYPack_() { less_half_edge lessElm(&x_, &just_before_, &evalAtXforYPack_); scan_data_ = scanline_type(lessElm); } inline scanline(const scanline& that) : scan_data_(), removal_set_(), insertion_set_(), end_point_queue_(), x_((std::numeric_limits<Unit>::max)()), y_((std::numeric_limits<Unit>::max)()), just_before_(false), evalAtXforYPack_() { (*this) = that; } inline scanline& operator=(const scanline& that) { x_ = that.x_; y_ = that.y_; just_before_ = that.just_before_; end_point_queue_ = that.end_point_queue_; //I cannot simply copy that.scanline_type to this scanline_type becuase the functor store pointers to other members! less_half_edge lessElm(&x_, &just_before_); scan_data_ = scanline_type(lessElm); scan_data_.insert(that.scan_data_.begin(), that.scan_data_.end()); return *this; } template <typename result_type, typename result_functor> void write_out(result_type& result, result_functor rf, const half_edge& he, const property_map& pm_left, const property_map& pm_right) { //std::cout << "write out "; //std::cout << he.first << ", " << he.second << "\n"; property_set ps_left, ps_right; set_unique_property(ps_left, pm_left); set_unique_property(ps_right, pm_right); if(ps_left != ps_right) { //std::cout << "!equivalent\n"; rf(result, he, ps_left, ps_right); } } template <typename result_type, typename result_functor, typename iT> iT handle_input_events(result_type& result, result_functor rf, iT begin, iT end) { //typedef typename high_precision_type<Unit>::type high_precision; //for each event property_map vertical_properties_above; property_map vertical_properties_below; half_edge vertical_edge_above; half_edge vertical_edge_below; std::vector<scanline_element> insertion_elements; //current_iter should increase monotonically toward end as we process scanline stop iterator current_iter = scan_data_.begin(); just_before_ = true; Unit y = (std::numeric_limits<Unit>::min)(); bool first_iteration = true; //we want to return from inside the loop when we hit end or new x #ifdef BOOST_POLYGON_MSVC #pragma warning (push) #pragma warning (disable: 4127) #endif while(true) { if(begin == end || (!first_iteration && ((*begin).first.first.get(VERTICAL) != y || (*begin).first.first.get(HORIZONTAL) != x_))) { //lookup iterator range in scanline for elements coming in from the left //that end at this y Point pt(x_, y); //grab the properties coming in from below property_map properties_below; if(current_iter != scan_data_.end()) { //make sure we are looking at element in scanline just below y //if(evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) != y) { if(scanline_base<Unit>::on_above_or_below(Point(x_, y), (*current_iter).first) != 0) { Point e2(pt); if(e2.get(VERTICAL) != (std::numeric_limits<Unit>::max)()) e2.set(VERTICAL, e2.get(VERTICAL) + 1); else e2.set(VERTICAL, e2.get(VERTICAL) - 1); half_edge vhe(pt, e2); current_iter = scan_data_.lower_bound(vhe); } if(current_iter != scan_data_.end()) { //get the bottom iterator for elements at this point //while(evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) >= (high_precision)y && while(scanline_base<Unit>::on_above_or_below(Point(x_, y), (*current_iter).first) != 1 && current_iter != scan_data_.begin()) { --current_iter; } //if(evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) >= (high_precision)y) { if(scanline_base<Unit>::on_above_or_below(Point(x_, y), (*current_iter).first) != 1) { properties_below.clear(); } else { properties_below = (*current_iter).second; //move back up to y or one past y ++current_iter; } } } std::vector<iterator> edges_from_left; while(current_iter != scan_data_.end() && //can only be true if y is integer //evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) == y) { scanline_base<Unit>::on_above_or_below(Point(x_, y), (*current_iter).first) == 0) { //removal_set_.push_back(current_iter); ++current_iter; } //merge vertical count with count from below if(!vertical_properties_below.empty()) { merge_property_maps(vertical_properties_below, properties_below); //write out vertical edge write_out(result, rf, vertical_edge_below, properties_below, vertical_properties_below); } else { merge_property_maps(vertical_properties_below, properties_below); } //iteratively add intertion element counts to count from below //and write them to insertion set for(std::size_t i = 0; i < insertion_elements.size(); ++i) { if(i == 0) { merge_property_maps(insertion_elements[i].second, vertical_properties_below); write_out(result, rf, insertion_elements[i].first, insertion_elements[i].second, vertical_properties_below); } else { merge_property_maps(insertion_elements[i].second, insertion_elements[i-1].second); write_out(result, rf, insertion_elements[i].first, insertion_elements[i].second, insertion_elements[i-1].second); } insertion_set_.push_back(insertion_elements[i]); } if((begin == end || (*begin).first.first.get(HORIZONTAL) != x_)) { if(vertical_properties_above.empty()) { return begin; } else { y = vertical_edge_above.second.get(VERTICAL); vertical_properties_below.clear(); vertical_properties_above.swap(vertical_properties_below); vertical_edge_below = vertical_edge_above; insertion_elements.clear(); continue; } } vertical_properties_below.clear(); vertical_properties_above.swap(vertical_properties_below); vertical_edge_below = vertical_edge_above; insertion_elements.clear(); } if(begin != end) { const vertex_property& vp = *begin; const half_edge& he = vp.first; y = he.first.get(VERTICAL); first_iteration = false; if(! vertical_properties_below.empty() && vertical_edge_below.second.get(VERTICAL) < y) { y = vertical_edge_below.second.get(VERTICAL); continue; } if(scanline_base<Unit>::is_vertical(he)) { update_property_map(vertical_properties_above, vp.second); vertical_edge_above = he; } else { if(insertion_elements.empty() || insertion_elements.back().first != he) { insertion_elements.push_back(scanline_element(he, property_map())); } update_property_map(insertion_elements.back().second, vp.second); } ++begin; } } #ifdef BOOST_POLYGON_MSVC #pragma warning (pop) #endif } inline void erase_end_events(typename end_point_queue::iterator epqi) { end_point_queue_.erase(end_point_queue_.begin(), epqi); for(typename std::vector<iterator>::iterator retire_itr = removal_set_.begin(); retire_itr != removal_set_.end(); ++retire_itr) { scan_data_.erase(*retire_itr); } removal_set_.clear(); } inline void remove_retired_edges_from_scanline() { just_before_ = true; typename end_point_queue::iterator epqi = end_point_queue_.begin(); Unit current_x = x_; Unit previous_x = x_; while(epqi != end_point_queue_.end() && (*epqi).get(HORIZONTAL) <= current_x) { x_ = (*epqi).get(HORIZONTAL); if(x_ != previous_x) erase_end_events(epqi); previous_x = x_; //lookup elements Point e2(*epqi); if(e2.get(VERTICAL) != (std::numeric_limits<Unit>::max)()) e2.set(VERTICAL, e2.get(VERTICAL) + 1); else e2.set(VERTICAL, e2.get(VERTICAL) - 1); half_edge vhe_e(*epqi, e2); iterator current_iter = scan_data_.lower_bound(vhe_e); while(current_iter != scan_data_.end() && (*current_iter).first.second == (*epqi)) { //evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) == (*epqi).get(VERTICAL)) { removal_set_.push_back(current_iter); ++current_iter; } ++epqi; } x_ = current_x; erase_end_events(epqi); } inline void insert_new_edges_into_scanline() { just_before_ = false; for(typename std::vector<scanline_element>::iterator insert_itr = insertion_set_.begin(); insert_itr != insertion_set_.end(); ++insert_itr) { scan_data_.insert(*insert_itr); end_point_queue_.insert((*insert_itr).first.second); } insertion_set_.clear(); } //iterator over range of vertex property elements and call result functor //passing edge to be output, the merged data on both sides and the result template <typename result_type, typename result_functor, typename iT> void scan(result_type& result, result_functor rf, iT begin, iT end) { while(begin != end) { x_ = (*begin).first.first.get(HORIZONTAL); //update scanline stop location //print_scanline(); --x_; remove_retired_edges_from_scanline(); ++x_; begin = handle_input_events(result, rf, begin, end); remove_retired_edges_from_scanline(); //print_scanline(); insert_new_edges_into_scanline(); } //print_scanline(); x_ = (std::numeric_limits<Unit>::max)(); remove_retired_edges_from_scanline(); } //inline void print_scanline() { // std::cout << "scanline at " << x_ << ": "; // for(iterator itr = scan_data_.begin(); itr != scan_data_.end(); ++itr) { // const scanline_element& se = *itr; // const half_edge& he = se.first; // const property_map& mp = se.second; // std::cout << he.first << ", " << he.second << " ( "; // for(std::size_t i = 0; i < mp.size(); ++i) { // std::cout << mp[i].first << ":" << mp[i].second << " "; // } std::cout << ") "; // } std::cout << "\n"; //} static inline void merge_property_maps(property_map& mp, const property_map& mp2) { property_map newmp; newmp.reserve(mp.size() + mp2.size()); unsigned int i = 0; unsigned int j = 0; while(i != mp.size() && j != mp2.size()) { if(mp[i].first < mp2[j].first) { newmp.push_back(mp[i]); ++i; } else if(mp[i].first > mp2[j].first) { newmp.push_back(mp2[j]); ++j; } else { int count = mp[i].second; count += mp2[j].second; if(count) { newmp.push_back(mp[i]); newmp.back().second = count; } ++i; ++j; } } while(i != mp.size()) { newmp.push_back(mp[i]); ++i; } while(j != mp2.size()) { newmp.push_back(mp2[j]); ++j; } mp.swap(newmp); } static inline void update_property_map(property_map& mp, const std::pair<property_type, int>& prop_data) { property_map newmp; newmp.reserve(mp.size() +1); bool consumed = false; for(std::size_t i = 0; i < mp.size(); ++i) { if(!consumed && prop_data.first == mp[i].first) { consumed = true; int count = prop_data.second + mp[i].second; if(count) newmp.push_back(std::make_pair(prop_data.first, count)); } else if(!consumed && prop_data.first < mp[i].first) { consumed = true; newmp.push_back(prop_data); newmp.push_back(mp[i]); } else { newmp.push_back(mp[i]); } } if(!consumed) newmp.push_back(prop_data); mp.swap(newmp); } static inline void set_unique_property(property_set& unqiue_property, const property_map& property) { unqiue_property.clear(); for(typename property_map::const_iterator itr = property.begin(); itr != property.end(); ++itr) { if((*itr).second > 0) unqiue_property.insert(unqiue_property.end(), (*itr).first); } } static inline bool common_vertex(const half_edge& he1, const half_edge& he2) { return he1.first == he2.first || he1.first == he2.second || he1.second == he2.first || he1.second == he2.second; } typedef typename scanline_base<Unit>::vertex_half_edge vertex_half_edge; template <typename iT> static inline void convert_segments_to_vertex_half_edges(std::vector<vertex_half_edge>& output, iT begin, iT end) { for( ; begin != end; ++begin) { const half_edge& he = (*begin).first; int count = (*begin).second; output.push_back(vertex_half_edge(he.first, he.second, count)); output.push_back(vertex_half_edge(he.second, he.first, -count)); } polygon_sort(output.begin(), output.end()); } class test_functor { public: inline test_functor() {} inline void operator()(std::vector<std::pair<half_edge, std::pair<property_set, property_set> > >& result, const half_edge& he, const property_set& ps_left, const property_set& ps_right) { result.push_back(std::make_pair(he, std::make_pair(ps_left, ps_right))); } }; template <typename stream_type> static inline bool test_scanline(stream_type& stdcout) { std::vector<std::pair<half_edge, std::pair<property_set, property_set> > > result; std::vector<std::pair<half_edge, std::pair<property_type, int> > > input; input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); input.push_back(std::make_pair(half_edge(Point(10, 0), Point(10, 10)), std::make_pair(0, -1))); scanline sl; test_functor tf; sl.scan(result, tf, input.begin(), input.end()); stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; } stdcout << "\n"; input.clear(); result.clear(); input.push_back(std::make_pair(half_edge(Point(-1, -1), Point(10, 0)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(-1, -1), Point(0, 10)), std::make_pair(0, -1))); input.push_back(std::make_pair(half_edge(Point(0, 10), Point(11, 11)), std::make_pair(0, -1))); input.push_back(std::make_pair(half_edge(Point(10, 0), Point(11, 11)), std::make_pair(0, 1))); scanline sl2; sl2.scan(result, tf, input.begin(), input.end()); stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; } stdcout << "\n"; input.clear(); result.clear(); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); input.push_back(std::make_pair(half_edge(Point(1, 1), Point(8, 2)), std::make_pair(1, 1))); input.push_back(std::make_pair(half_edge(Point(1, 1), Point(2, 8)), std::make_pair(1, -1))); input.push_back(std::make_pair(half_edge(Point(2, 8), Point(9, 9)), std::make_pair(1, -1))); input.push_back(std::make_pair(half_edge(Point(8, 2), Point(9, 9)), std::make_pair(1, 1))); input.push_back(std::make_pair(half_edge(Point(10, 0), Point(10, 10)), std::make_pair(0, -1))); scanline sl3; sl3.scan(result, tf, input.begin(), input.end()); stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; } stdcout << "\n"; input.clear(); result.clear(); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); input.push_back(std::make_pair(half_edge(Point(1, 1), Point(8, 2)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(1, 1), Point(2, 8)), std::make_pair(0, -1))); input.push_back(std::make_pair(half_edge(Point(2, 8), Point(9, 9)), std::make_pair(0, -1))); input.push_back(std::make_pair(half_edge(Point(8, 2), Point(9, 9)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(10, 0), Point(10, 10)), std::make_pair(0, -1))); scanline sl4; sl4.scan(result, tf, input.begin(), input.end()); stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; } stdcout << "\n"; input.clear(); result.clear(); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(9, 1)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(1, 9)), std::make_pair(0, -1))); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); input.push_back(std::make_pair(half_edge(Point(1, 9), Point(10, 10)), std::make_pair(0, -1))); input.push_back(std::make_pair(half_edge(Point(9, 1), Point(10, 10)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(10, 0), Point(10, 10)), std::make_pair(0, -1))); scanline sl5; sl5.scan(result, tf, input.begin(), input.end()); stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; } stdcout << "\n"; input.clear(); result.clear(); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(9, 1)), std::make_pair(1, 1))); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(1, 9)), std::make_pair(1, -1))); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); input.push_back(std::make_pair(half_edge(Point(1, 9), Point(10, 10)), std::make_pair(1, -1))); input.push_back(std::make_pair(half_edge(Point(9, 1), Point(10, 10)), std::make_pair(1, 1))); input.push_back(std::make_pair(half_edge(Point(10, 0), Point(10, 10)), std::make_pair(0, -1))); scanline sl6; sl6.scan(result, tf, input.begin(), input.end()); stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; } stdcout << "\n"; input.clear(); result.clear(); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(9, 1)), std::make_pair(1, 1))); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(1, 9)), std::make_pair(1, -1))); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); input.push_back(std::make_pair(half_edge(Point(0, 20), Point(10, 20)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(0, 20), Point(9, 21)), std::make_pair(1, 1))); input.push_back(std::make_pair(half_edge(Point(0, 20), Point(1, 29)), std::make_pair(1, -1))); input.push_back(std::make_pair(half_edge(Point(0, 20), Point(0, 30)), std::make_pair(0, 1))); input.push_back(std::make_pair(half_edge(Point(0, 30), Point(10, 30)), std::make_pair(0, -1))); input.push_back(std::make_pair(half_edge(Point(1, 9), Point(10, 10)), std::make_pair(1, -1))); input.push_back(std::make_pair(half_edge(Point(1, 29), Point(10, 30)), std::make_pair(1, -1))); input.push_back(std::make_pair(half_edge(Point(9, 1), Point(10, 10)), std::make_pair(1, 1))); input.push_back(std::make_pair(half_edge(Point(9, 21), Point(10, 30)), std::make_pair(1, 1))); input.push_back(std::make_pair(half_edge(Point(10, 20), Point(10, 30)), std::make_pair(0, -1))); input.push_back(std::make_pair(half_edge(Point(10, 20), Point(10, 30)), std::make_pair(0, -1))); scanline sl7; sl7.scan(result, tf, input.begin(), input.end()); stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; } stdcout << "\n"; input.clear(); result.clear(); input.push_back(std::make_pair(half_edge(Point(-1, -1), Point(10, 0)), std::make_pair(0, 1))); //a input.push_back(std::make_pair(half_edge(Point(-1, -1), Point(0, 10)), std::make_pair(0, -1))); //a input.push_back(std::make_pair(half_edge(Point(0, 10), Point(11, 11)), std::make_pair(0, -1))); //a input.push_back(std::make_pair(half_edge(Point(10, 0), Point(20, 0)), std::make_pair(0, 1))); //b input.push_back(std::make_pair(half_edge(Point(10, 0), Point(11, 11)), std::make_pair(0, -1))); //b input.push_back(std::make_pair(half_edge(Point(10, 0), Point(11, 11)), std::make_pair(0, 1))); //a input.push_back(std::make_pair(half_edge(Point(11, 11), Point(20, 10)), std::make_pair(0, -1))); //b input.push_back(std::make_pair(half_edge(Point(20, 0), Point(30, 0)), std::make_pair(0, 1))); //c input.push_back(std::make_pair(half_edge(Point(20, 0), Point(20, 10)), std::make_pair(0, -1))); //b input.push_back(std::make_pair(half_edge(Point(20, 0), Point(20, 10)), std::make_pair(0, 1))); //c input.push_back(std::make_pair(half_edge(Point(20, 10), Point(30, 10)), std::make_pair(0, -1))); //c input.push_back(std::make_pair(half_edge(Point(30, 0), Point(30, 10)), std::make_pair(0, -1))); //c scanline sl8; sl8.scan(result, tf, input.begin(), input.end()); stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; } stdcout << "\n"; return true; } }; template <typename Unit> class merge_output_functor { public: typedef typename scanline_base<Unit>::half_edge half_edge; merge_output_functor() {} template <typename result_type, typename key_type> void operator()(result_type& result, const half_edge& edge, const key_type& left, const key_type& right) { typename std::pair<half_edge, int> elem; elem.first = edge; elem.second = 1; if(edge.second < edge.first) elem.second *= -1; if(scanline_base<Unit>::is_vertical(edge)) elem.second *= -1; if(!left.empty()) result[left].insert_clean(elem); elem.second *= -1; if(!right.empty()) result[right].insert_clean(elem); } }; template <typename Unit, typename property_type, typename key_type = std::set<property_type>, typename output_functor_type = merge_output_functor<Unit> > class property_merge : public scanline_base<Unit> { protected: typedef typename scanline_base<Unit>::Point Point; //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex //typedef std::pair<Point, Point> half_edge; typedef typename scanline_base<Unit>::half_edge half_edge; //scanline comparator functor typedef typename scanline_base<Unit>::less_half_edge less_half_edge; typedef typename scanline_base<Unit>::less_point less_point; //this data structure assocates a property and count to a half edge typedef std::pair<half_edge, std::pair<property_type, int> > vertex_property; //this data type stores the combination of many half edges typedef std::vector<vertex_property> property_merge_data; //this is the data type used internally to store the combination of property counts at a given location typedef std::vector<std::pair<property_type, int> > property_map; //this data type is used internally to store the combined property data for a given half edge typedef std::pair<half_edge, property_map> vertex_data; property_merge_data pmd; typename scanline_base<Unit>::evalAtXforYPack evalAtXforYPack_; template<typename vertex_data_type> class less_vertex_data { typename scanline_base<Unit>::evalAtXforYPack* pack_; public: less_vertex_data() : pack_() {} less_vertex_data(typename scanline_base<Unit>::evalAtXforYPack* pack) : pack_(pack) {} bool operator() (const vertex_data_type& lvalue, const vertex_data_type& rvalue) const { less_point lp; if(lp(lvalue.first.first, rvalue.first.first)) return true; if(lp(rvalue.first.first, lvalue.first.first)) return false; Unit x = lvalue.first.first.get(HORIZONTAL); int just_before_ = 0; less_half_edge lhe(&x, &just_before_, pack_); return lhe(lvalue.first, rvalue.first); } }; inline void sort_property_merge_data() { less_vertex_data<vertex_property> lvd(&evalAtXforYPack_); polygon_sort(pmd.begin(), pmd.end(), lvd); } public: inline property_merge_data& get_property_merge_data() { return pmd; } inline property_merge() : pmd(), evalAtXforYPack_() {} inline property_merge(const property_merge& pm) : pmd(pm.pmd), evalAtXforYPack_(pm.evalAtXforYPack_) {} inline property_merge& operator=(const property_merge& pm) { pmd = pm.pmd; return *this; } template <typename polygon_type> void insert(const polygon_type& polygon_object, const property_type& property_value, bool is_hole = false) { insert(polygon_object, property_value, is_hole, typename geometry_concept<polygon_type>::type()); } //result type should be std::map<std::set<property_type>, polygon_set_type> //or std::map<std::vector<property_type>, polygon_set_type> template <typename result_type> void merge(result_type& result) { if(pmd.empty()) return; //intersect data property_merge_data tmp_pmd; line_intersection<Unit>::validate_scan(tmp_pmd, pmd.begin(), pmd.end()); pmd.swap(tmp_pmd); sort_property_merge_data(); scanline<Unit, property_type, key_type> sl; output_functor_type mof; sl.scan(result, mof, pmd.begin(), pmd.end()); } inline bool verify1() { std::pair<int, int> offenders; std::vector<std::pair<half_edge, int> > lines; int count = 0; for(std::size_t i = 0; i < pmd.size(); ++i) { lines.push_back(std::make_pair(pmd[i].first, count++)); } if(!line_intersection<Unit>::verify_scan(offenders, lines.begin(), lines.end())) { //stdcout << "Intersection failed!\n"; //stdcout << offenders.first << " " << offenders.second << "\n"; return false; } std::vector<Point> pts; for(std::size_t i = 0; i < lines.size(); ++i) { pts.push_back(lines[i].first.first); pts.push_back(lines[i].first.second); } polygon_sort(pts.begin(), pts.end()); for(std::size_t i = 0; i < pts.size(); i+=2) { if(pts[i] != pts[i+1]) { //stdcout << "Non-closed figures after line intersection!\n"; return false; } } return true; } void clear() {*this = property_merge();} protected: template <typename polygon_type> void insert(const polygon_type& polygon_object, const property_type& property_value, bool is_hole, polygon_concept ) { bool first_iteration = true; bool second_iteration = true; Point first_point; Point second_point; Point previous_previous_point; Point previous_point; Point current_point; direction_1d winding_dir = winding(polygon_object); for(typename polygon_traits<polygon_type>::iterator_type itr = begin_points(polygon_object); itr != end_points(polygon_object); ++itr) { assign(current_point, *itr); if(first_iteration) { first_iteration = false; first_point = previous_point = current_point; } else if(second_iteration) { if(previous_point != current_point) { second_iteration = false; previous_previous_point = previous_point; second_point = previous_point = current_point; } } else { if(previous_point != current_point) { create_vertex(pmd, previous_point, current_point, winding_dir, is_hole, property_value); previous_previous_point = previous_point; previous_point = current_point; } } } current_point = first_point; if(!first_iteration && !second_iteration) { if(previous_point != current_point) { create_vertex(pmd, previous_point, current_point, winding_dir, is_hole, property_value); previous_previous_point = previous_point; previous_point = current_point; } current_point = second_point; create_vertex(pmd, previous_point, current_point, winding_dir, is_hole, property_value); previous_previous_point = previous_point; previous_point = current_point; } } template <typename polygon_with_holes_type> void insert(const polygon_with_holes_type& polygon_with_holes_object, const property_type& property_value, bool is_hole, polygon_with_holes_concept) { insert(polygon_with_holes_object, property_value, is_hole, polygon_concept()); for(typename polygon_with_holes_traits<polygon_with_holes_type>::iterator_holes_type itr = begin_holes(polygon_with_holes_object); itr != end_holes(polygon_with_holes_object); ++itr) { insert(*itr, property_value, !is_hole, polygon_concept()); } } template <typename rectangle_type> void insert(const rectangle_type& rectangle_object, const property_type& property_value, bool is_hole, rectangle_concept ) { polygon_90_data<Unit> poly; assign(poly, rectangle_object); insert(poly, property_value, is_hole, polygon_concept()); } public: //change to private when done testing static inline void create_vertex(property_merge_data& pmd, const Point& current_point, const Point& next_point, direction_1d winding, bool is_hole, const property_type& property) { if(current_point == next_point) return; vertex_property current_vertex; current_vertex.first.first = current_point; current_vertex.first.second = next_point; current_vertex.second.first = property; int multiplier = 1; if(winding == CLOCKWISE) multiplier = -1; if(is_hole) multiplier *= -1; if(current_point < next_point) { multiplier *= -1; std::swap(current_vertex.first.first, current_vertex.first.second); } current_vertex.second.second = multiplier * (euclidean_distance(next_point, current_point, HORIZONTAL) == 0 ? -1: 1); pmd.push_back(current_vertex); //current_vertex.first.second = previous_point; //current_vertex.second.second *= -1; //pmd.push_back(current_vertex); } static inline void sort_vertex_half_edges(vertex_data& vertex) { less_half_edge_pair lessF(vertex.first); polygon_sort(vertex.second.begin(), vertex.second.end(), lessF); } class less_half_edge_pair { private: Point pt_; public: less_half_edge_pair(const Point& pt) : pt_(pt) {} bool operator()(const half_edge& e1, const half_edge& e2) { const Point& pt1 = e1.first; const Point& pt2 = e2.first; if(get(pt1, HORIZONTAL) == get(pt_, HORIZONTAL)) { //vertical edge is always largest return false; } if(get(pt2, HORIZONTAL) == get(pt_, HORIZONTAL)) { //if half edge 1 is not vertical its slope is less than that of half edge 2 return get(pt1, HORIZONTAL) != get(pt2, HORIZONTAL); } return scanline_base<Unit>::less_slope(get(pt_, HORIZONTAL), get(pt_, VERTICAL), pt1, pt2); } }; public: //test functions template <typename stream_type> static stream_type& print (stream_type& o, const property_map& c) { o << "count: {"; for(typename property_map::const_iterator itr = c.begin(); itr != c.end(); ++itr) { o << ((*itr).first) << ":" << ((*itr).second) << " "; } return o << "} "; } template <typename stream_type> static stream_type& print (stream_type& o, const half_edge& he) { o << "half edge: ("; o << (he.first); return o << ", " << (he.second) << ") "; } template <typename stream_type> static stream_type& print (stream_type& o, const vertex_property& c) { o << "vertex property: {"; print(o, c.first); o << ", " << c.second.first << ":" << c.second.second << " "; return o; } template <typename stream_type> static stream_type& print (stream_type& o, const std::vector<vertex_property>& hev) { o << "vertex properties: {"; for(std::size_t i = 0; i < hev.size(); ++i) { print(o, (hev[i])) << " "; } return o << "} "; } template <typename stream_type> static stream_type& print (stream_type& o, const std::vector<half_edge>& hev) { o << "half edges: {"; for(std::size_t i = 0; i < hev.size(); ++i) { print(o, (hev[i])) << " "; } return o << "} "; } template <typename stream_type> static stream_type& print (stream_type& o, const vertex_data& v) { return print(o << "vertex: <" << (v.first) << ", ", (v.second)) << "> "; } template <typename stream_type> static stream_type& print (stream_type& o, const std::vector<vertex_data>& vv) { o << "vertices: {"; for(std::size_t i = 0; i < vv.size(); ++i) { print(o, (vv[i])) << " "; } return o << "} "; } template <typename stream_type> static inline bool test_insertion(stream_type& stdcout) { property_merge si; rectangle_data<Unit> rect; xl(rect, 0); yl(rect, 1); xh(rect, 10); yh(rect, 11); si.insert(rect, 333); print(stdcout, si.pmd) << "\n"; Point pts[4] = {Point(0, 0), Point(10,-3), Point(13, 8), Point(0, 0) }; polygon_data<Unit> poly; property_merge si2; poly.set(pts, pts+3); si2.insert(poly, 444); si2.sort_property_merge_data(); print(stdcout, si2.pmd) << "\n"; property_merge si3; poly.set(pts, pts+4); si3.insert(poly, 444); si3.sort_property_merge_data(); stdcout << (si2.pmd == si3.pmd) << "\n"; std::reverse(pts, pts+4); property_merge si4; poly.set(pts, pts+4); si4.insert(poly, 444); si4.sort_property_merge_data(); print(stdcout, si4.pmd) << "\n"; stdcout << (si2.pmd == si4.pmd) << "\n"; std::reverse(pts, pts+3); property_merge si5; poly.set(pts, pts+4); si5.insert(poly, 444); si5.sort_property_merge_data(); stdcout << (si2.pmd == si5.pmd) << "\n"; return true; } template <typename stream_type> static inline bool test_merge(stream_type& stdcout) { property_merge si; rectangle_data<Unit> rect; xl(rect, 0); yl(rect, 1); xh(rect, 10); yh(rect, 11); si.insert(rect, 333); std::map<std::set<property_type>, polygon_set_data<Unit> > result; si.merge(result); print(stdcout, si.pmd) << "\n"; polygon_set_data<Unit> psd = (*(result.begin())).second; std::vector<polygon_data<Unit> > polys; psd.get(polys); if(polys.size() != 1) { stdcout << "fail merge 1\n"; return false; } stdcout << (polys[0]) << "\n"; si.clear(); std::vector<Point> pts; pts.push_back(Point(0, 0)); pts.push_back(Point(10, -10)); pts.push_back(Point(10, 10)); polygon_data<Unit> poly; poly.set(pts.begin(), pts.end()); si.insert(poly, 444); pts.clear(); pts.push_back(Point(5, 0)); pts.push_back(Point(-5, -10)); pts.push_back(Point(-5, 10)); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); result.clear(); si.merge(result); print(stdcout, si.pmd) << "\n"; psd = (*(result.begin())).second; stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() != 1) { stdcout << "fail merge 2\n"; return false; } //Polygon { -4 -1, 3 3, -2 3 } //Polygon { 0 -4, -4 -2, -2 1 } si.clear(); pts.clear(); pts.push_back(Point(-4, -1)); pts.push_back(Point(3, 3)); pts.push_back(Point(-2, 3)); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); pts.clear(); pts.push_back(Point(0, -4)); pts.push_back(Point(-4, -2)); pts.push_back(Point(-2, 1)); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); result.clear(); si.merge(result); print(stdcout, si.pmd) << "\n"; psd = (*(result.begin())).second; stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() != 1) { stdcout << "fail merge 3\n"; return false; } stdcout << "Polygon { -2 2, -2 2, 1 4 } \n"; stdcout << "Polygon { 2 4, 2 -4, -3 1 } \n"; si.clear(); pts.clear(); pts.push_back(Point(-2, 2)); pts.push_back(Point(-2, 2)); pts.push_back(Point(1, 4)); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); pts.clear(); pts.push_back(Point(2, 4)); pts.push_back(Point(2, -4)); pts.push_back(Point(-3, 1)); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); result.clear(); si.merge(result); print(stdcout, si.pmd) << "\n"; psd = (*(result.begin())).second; stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() != 1) { stdcout << "fail merge 4\n"; return false; } stdcout << (polys[0]) << "\n"; stdcout << "Polygon { -4 0, -2 -3, 3 -4 } \n"; stdcout << "Polygon { -1 1, 1 -2, -4 -3 } \n"; si.clear(); pts.clear(); pts.push_back(Point(-4, 0)); pts.push_back(Point(-2, -3)); pts.push_back(Point(3, -4)); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); pts.clear(); pts.push_back(Point(-1, 1)); pts.push_back(Point(1, -2)); pts.push_back(Point(-4, -3)); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); result.clear(); si.merge(result); print(stdcout, si.pmd) << "\n"; psd = (*(result.begin())).second; stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() != 1) { stdcout << "fail merge 5\n"; return false; } stdcout << "Polygon { 2 2, -2 0, 0 1 } \n"; stdcout << "Polygon { 4 -2, 3 -1, 2 3 } \n"; si.clear(); pts.clear(); pts.push_back(Point(2, 2)); pts.push_back(Point(-2, 0)); pts.push_back(Point(0, 1)); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); pts.clear(); pts.push_back(Point(4, -2)); pts.push_back(Point(3, -1)); pts.push_back(Point(2, 3)); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); result.clear(); si.merge(result); print(stdcout, si.pmd) << "\n"; if(!result.empty()) { psd = (*(result.begin())).second; stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() != 1) { stdcout << "fail merge 6\n"; return false; } stdcout << (polys[0]) << "\n"; } stdcout << "Polygon { 0 2, 3 -1, 4 1 } \n"; stdcout << "Polygon { -4 3, 3 3, 4 2 } \n"; si.clear(); pts.clear(); pts.push_back(Point(0, 2)); pts.push_back(Point(3, -1)); pts.push_back(Point(4, 1)); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); pts.clear(); pts.push_back(Point(-4, 3)); pts.push_back(Point(3, 3)); pts.push_back(Point(4, 2)); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); result.clear(); si.merge(result); print(stdcout, si.pmd) << "\n"; if(!result.empty()) { psd = (*(result.begin())).second; stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() == 0) { stdcout << "fail merge 7\n"; return false; } stdcout << (polys[0]) << "\n"; } stdcout << "Polygon { 1 -2, -1 4, 3 -2 } \n"; stdcout << "Polygon { 0 -3, 3 1, -3 -4 } \n"; si.clear(); pts.clear(); pts.push_back(Point(1, -2)); pts.push_back(Point(-1, 4)); pts.push_back(Point(3, -2)); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); pts.clear(); pts.push_back(Point(0, -3)); pts.push_back(Point(3, 1)); pts.push_back(Point(-3, -4)); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); result.clear(); si.merge(result); print(stdcout, si.pmd) << "\n"; if(!result.empty()) { psd = (*(result.begin())).second; stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() == 0) { stdcout << "fail merge 8\n"; return false; } stdcout << (polys[0]) << "\n"; } stdcout << "Polygon { 2 2, 3 0, -3 4 } \n"; stdcout << "Polygon { -2 -2, 0 0, -1 -1 } \n"; si.clear(); pts.clear(); pts.push_back(Point(2, 2)); pts.push_back(Point(3, 0)); pts.push_back(Point(-3, 4)); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); pts.clear(); pts.push_back(Point(-2, -2)); pts.push_back(Point(0, 0)); pts.push_back(Point(-1, -1)); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); result.clear(); si.merge(result); print(stdcout, si.pmd) << "\n"; if(!result.empty()) { psd = (*(result.begin())).second; stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() == 0) { stdcout << "fail merge 9\n"; return false; } stdcout << (polys[0]) << "\n"; } si.clear(); pts.clear(); //5624841,17616200,75000,9125000 //pts.push_back(Point(5624841,75000)); //pts.push_back(Point(5624841,9125000)); //pts.push_back(Point(17616200,9125000)); //pts.push_back(Point(17616200,75000)); pts.push_back(Point(12262940, 6652520 )); pts.push_back(Point(12125750, 6652520 )); pts.push_back(Point(12121272, 6652961 )); pts.push_back(Point(12112981, 6656396 )); pts.push_back(Point(12106636, 6662741 )); pts.push_back(Point(12103201, 6671032 )); pts.push_back(Point(12103201, 6680007 )); pts.push_back(Point(12106636, 6688298 )); pts.push_back(Point(12109500, 6691780 )); pts.push_back(Point(12748600, 7330890 )); pts.push_back(Point(15762600, 7330890 )); pts.push_back(Point(15904620, 7472900 )); pts.push_back(Point(15909200, 7473030 )); pts.push_back(Point(15935830, 7476006 )); pts.push_back(Point(15992796, 7499602 )); pts.push_back(Point(16036397, 7543203 )); pts.push_back(Point(16059993, 7600169 )); pts.push_back(Point(16059993, 7661830 )); pts.push_back(Point(16036397, 7718796 )); pts.push_back(Point(15992796, 7762397 )); pts.push_back(Point(15935830, 7785993 )); pts.push_back(Point(15874169, 7785993 )); pts.push_back(Point(15817203, 7762397 )); pts.push_back(Point(15773602, 7718796 )); pts.push_back(Point(15750006, 7661830 )); pts.push_back(Point(15747030, 7635200 )); pts.push_back(Point(15746900, 7630620 )); pts.push_back(Point(15670220, 7553930 )); pts.push_back(Point(14872950, 7553930 )); pts.push_back(Point(14872950, 7626170 )); pts.push_back(Point(14869973, 7661280 )); pts.push_back(Point(14846377, 7718246 )); pts.push_back(Point(14802776, 7761847 )); pts.push_back(Point(14745810, 7785443 )); pts.push_back(Point(14684149, 7785443 )); pts.push_back(Point(14627183, 7761847 )); pts.push_back(Point(14583582, 7718246 )); pts.push_back(Point(14559986, 7661280 )); pts.push_back(Point(14557070, 7636660 )); pts.push_back(Point(14556670, 7625570 )); pts.push_back(Point(13703330, 7625570 )); pts.push_back(Point(13702930, 7636660 )); pts.push_back(Point(13699993, 7661830 )); pts.push_back(Point(13676397, 7718796 )); pts.push_back(Point(13632796, 7762397 )); pts.push_back(Point(13575830, 7785993 )); pts.push_back(Point(13514169, 7785993 )); pts.push_back(Point(13457203, 7762397 )); pts.push_back(Point(13436270, 7745670 )); pts.push_back(Point(13432940, 7742520 )); pts.push_back(Point(12963760, 7742520 )); pts.push_back(Point(12959272, 7742961 )); pts.push_back(Point(12950981, 7746396 )); pts.push_back(Point(12944636, 7752741 )); pts.push_back(Point(12941201, 7761032 )); pts.push_back(Point(12941201, 7770007 )); pts.push_back(Point(12944636, 7778298 )); pts.push_back(Point(12947490, 7781780 )); pts.push_back(Point(13425330, 8259620 )); pts.push_back(Point(15601330, 8259620 )); pts.push_back(Point(15904620, 8562900 )); pts.push_back(Point(15909200, 8563030 )); pts.push_back(Point(15935830, 8566006 )); pts.push_back(Point(15992796, 8589602 )); pts.push_back(Point(16036397, 8633203 )); pts.push_back(Point(16059993, 8690169 )); pts.push_back(Point(16059993, 8751830 )); pts.push_back(Point(16036397, 8808796 )); pts.push_back(Point(15992796, 8852397 )); pts.push_back(Point(15935830, 8875993 )); pts.push_back(Point(15874169, 8875993 )); pts.push_back(Point(15817203, 8852397 )); pts.push_back(Point(15773602, 8808796 )); pts.push_back(Point(15750006, 8751830 )); pts.push_back(Point(15747030, 8725200 )); pts.push_back(Point(15746900, 8720620 )); pts.push_back(Point(15508950, 8482660 )); pts.push_back(Point(14689890, 8482660 )); pts.push_back(Point(14685412, 8483101 )); pts.push_back(Point(14677121, 8486536 )); pts.push_back(Point(14670776, 8492881 )); pts.push_back(Point(14667341, 8501172 )); pts.push_back(Point(14667341, 8510147 )); pts.push_back(Point(14670776, 8518438 )); pts.push_back(Point(14673630, 8521920 )); pts.push_back(Point(14714620, 8562900 )); pts.push_back(Point(14719200, 8563030 )); pts.push_back(Point(14745830, 8566006 )); pts.push_back(Point(14802796, 8589602 )); pts.push_back(Point(14846397, 8633203 )); pts.push_back(Point(14869993, 8690169 )); pts.push_back(Point(14869993, 8751830 )); pts.push_back(Point(14846397, 8808796 )); pts.push_back(Point(14802796, 8852397 )); pts.push_back(Point(14745830, 8875993 )); pts.push_back(Point(14684169, 8875993 )); pts.push_back(Point(14627203, 8852397 )); pts.push_back(Point(14583602, 8808796 )); pts.push_back(Point(14560006, 8751830 )); pts.push_back(Point(14557030, 8725200 )); pts.push_back(Point(14556900, 8720620 )); pts.push_back(Point(14408270, 8571980 )); pts.push_back(Point(13696320, 8571980 )); pts.push_back(Point(13696320, 8675520 )); pts.push_back(Point(13699963, 8690161 )); pts.push_back(Point(13699963, 8751818 )); pts.push_back(Point(13676368, 8808781 )); pts.push_back(Point(13632771, 8852378 )); pts.push_back(Point(13575808, 8875973 )); pts.push_back(Point(13514151, 8875973 )); pts.push_back(Point(13457188, 8852378 )); pts.push_back(Point(13436270, 8835670 )); pts.push_back(Point(13432940, 8832520 )); pts.push_back(Point(13281760, 8832520 )); pts.push_back(Point(13277272, 8832961 )); pts.push_back(Point(13268981, 8836396 )); pts.push_back(Point(13262636, 8842741 )); pts.push_back(Point(13259201, 8851032 )); pts.push_back(Point(13259201, 8860007 )); pts.push_back(Point(13262636, 8868298 )); pts.push_back(Point(13265500, 8871780 )); pts.push_back(Point(13518710, 9125000 )); pts.push_back(Point(16270720, 9125000 )); pts.push_back(Point(16270720, 8939590 )); pts.push_back(Point(17120780, 8939590 )); pts.push_back(Point(17120780, 9125000 )); pts.push_back(Point(17616200, 9125000 )); pts.push_back(Point(17616200, 75000 )); pts.push_back(Point(16024790, 75000 )); pts.push_back(Point(16021460, 80700 )); pts.push_back(Point(16016397, 88796 )); pts.push_back(Point(15972796, 132397 )); pts.push_back(Point(15915830, 155993 )); pts.push_back(Point(15908730, 157240 )); pts.push_back(Point(15905000, 157800 )); pts.push_back(Point(15516800, 546000 )); pts.push_back(Point(15905000, 934200 )); pts.push_back(Point(15908730, 934760 )); pts.push_back(Point(15915830, 936006 )); pts.push_back(Point(15972796, 959602 )); pts.push_back(Point(16016397, 1003203 )); pts.push_back(Point(16039993, 1060169 )); pts.push_back(Point(16039993, 1121830 )); pts.push_back(Point(16016397, 1178796 )); pts.push_back(Point(15972796, 1222397 )); pts.push_back(Point(15915830, 1245993 )); pts.push_back(Point(15854169, 1245993 )); pts.push_back(Point(15797203, 1222397 )); pts.push_back(Point(15753602, 1178796 )); pts.push_back(Point(15730006, 1121830 )); pts.push_back(Point(15728760, 1114730 )); pts.push_back(Point(15728200, 1111000 )); pts.push_back(Point(15363500, 746300 )); pts.push_back(Point(14602620, 746300 )); pts.push_back(Point(14598142, 746741 )); pts.push_back(Point(14589851, 750176 )); pts.push_back(Point(14583506, 756521 )); pts.push_back(Point(14580071, 764812 )); pts.push_back(Point(14580071, 773787 )); pts.push_back(Point(14583506, 782078 )); pts.push_back(Point(14586360, 785560 )); pts.push_back(Point(14586370, 785560 )); pts.push_back(Point(14735000, 934200 )); pts.push_back(Point(14738730, 934760 )); pts.push_back(Point(14745830, 936006 )); pts.push_back(Point(14802796, 959602 )); pts.push_back(Point(14846397, 1003203 )); pts.push_back(Point(14869993, 1060169 )); pts.push_back(Point(14870450, 1062550 )); pts.push_back(Point(14872170, 1071980 )); pts.push_back(Point(14972780, 1071980 )); pts.push_back(Point(15925000, 2024200 )); pts.push_back(Point(15928730, 2024760 )); pts.push_back(Point(15935830, 2026006 )); pts.push_back(Point(15992796, 2049602 )); pts.push_back(Point(16036397, 2093203 )); pts.push_back(Point(16059993, 2150169 )); pts.push_back(Point(16059993, 2211830 )); pts.push_back(Point(16036397, 2268796 )); pts.push_back(Point(15992796, 2312397 )); pts.push_back(Point(15935830, 2335993 )); pts.push_back(Point(15874169, 2335993 )); pts.push_back(Point(15817203, 2312397 )); pts.push_back(Point(15773602, 2268796 )); pts.push_back(Point(15750006, 2211830 )); pts.push_back(Point(15748760, 2204730 )); pts.push_back(Point(15748200, 2201000 )); pts.push_back(Point(14869220, 1322020 )); pts.push_back(Point(14088350, 1322020 )); pts.push_back(Point(14083862, 1322461 )); pts.push_back(Point(14075571, 1325896 )); pts.push_back(Point(14069226, 1332241 )); pts.push_back(Point(14065791, 1340532 )); pts.push_back(Point(14065791, 1349507 )); pts.push_back(Point(14069226, 1357798 )); pts.push_back(Point(14072080, 1361280 )); pts.push_back(Point(14072090, 1361280 )); pts.push_back(Point(14735000, 2024200 )); pts.push_back(Point(14738730, 2024760 )); pts.push_back(Point(14745830, 2026006 )); pts.push_back(Point(14802796, 2049602 )); pts.push_back(Point(14846397, 2093203 )); pts.push_back(Point(14869993, 2150169 )); pts.push_back(Point(14869993, 2211830 )); pts.push_back(Point(14846397, 2268796 )); pts.push_back(Point(14802796, 2312397 )); pts.push_back(Point(14745830, 2335993 )); pts.push_back(Point(14684169, 2335993 )); pts.push_back(Point(14627203, 2312397 )); pts.push_back(Point(14583602, 2268796 )); pts.push_back(Point(14560006, 2211830 )); pts.push_back(Point(14558760, 2204730 )); pts.push_back(Point(14558200, 2201000 )); pts.push_back(Point(13752220, 1395020 )); pts.push_back(Point(12991340, 1395020 )); pts.push_back(Point(12986862, 1395461 )); pts.push_back(Point(12978571, 1398896 )); pts.push_back(Point(12972226, 1405241 )); pts.push_back(Point(12968791, 1413532 )); pts.push_back(Point(12968791, 1422507 )); pts.push_back(Point(12972226, 1430798 )); pts.push_back(Point(12975080, 1434280 )); pts.push_back(Point(12975090, 1434280 )); pts.push_back(Point(13565000, 2024200 )); pts.push_back(Point(13568730, 2024760 )); pts.push_back(Point(13575830, 2026006 )); pts.push_back(Point(13632796, 2049602 )); pts.push_back(Point(13676397, 2093203 )); pts.push_back(Point(13699993, 2150169 )); pts.push_back(Point(13699993, 2211830 )); pts.push_back(Point(13676397, 2268796 )); pts.push_back(Point(13632796, 2312397 )); pts.push_back(Point(13575830, 2335993 )); pts.push_back(Point(13514169, 2335993 )); pts.push_back(Point(13457203, 2312397 )); pts.push_back(Point(13413602, 2268796 )); pts.push_back(Point(13390006, 2211830 )); pts.push_back(Point(13388760, 2204730 )); pts.push_back(Point(13388200, 2201000 )); pts.push_back(Point(12655220, 1468020 )); pts.push_back(Point(11894340, 1468020 )); pts.push_back(Point(11889862, 1468461 )); pts.push_back(Point(11881571, 1471896 )); pts.push_back(Point(11875226, 1478241 )); pts.push_back(Point(11871791, 1486532 )); pts.push_back(Point(11871791, 1495507 )); pts.push_back(Point(11875226, 1503798 )); pts.push_back(Point(11878090, 1507280 )); pts.push_back(Point(12395000, 2024200 )); pts.push_back(Point(12398730, 2024760 )); pts.push_back(Point(12405830, 2026006 )); pts.push_back(Point(12462796, 2049602 )); pts.push_back(Point(12506397, 2093203 )); pts.push_back(Point(12529993, 2150169 )); pts.push_back(Point(12529993, 2211830 )); pts.push_back(Point(12506397, 2268796 )); pts.push_back(Point(12462796, 2312397 )); pts.push_back(Point(12405830, 2335993 )); pts.push_back(Point(12344169, 2335993 )); pts.push_back(Point(12287203, 2312397 )); pts.push_back(Point(12243602, 2268796 )); pts.push_back(Point(12220006, 2211830 )); pts.push_back(Point(12218760, 2204730 )); pts.push_back(Point(12218200, 2201000 )); pts.push_back(Point(11558220, 1541020 )); pts.push_back(Point(10797340, 1541020 )); pts.push_back(Point(10792862, 1541461 )); pts.push_back(Point(10784571, 1544896 )); pts.push_back(Point(10778226, 1551241 )); pts.push_back(Point(10774791, 1559532 )); pts.push_back(Point(10774791, 1568507 )); pts.push_back(Point(10778226, 1576798 )); pts.push_back(Point(10781080, 1580280 )); pts.push_back(Point(10781090, 1580280 )); pts.push_back(Point(11225000, 2024200 )); pts.push_back(Point(11228730, 2024760 )); pts.push_back(Point(11235830, 2026006 )); pts.push_back(Point(11292796, 2049602 )); pts.push_back(Point(11336397, 2093203 )); pts.push_back(Point(11359993, 2150169 )); pts.push_back(Point(11359993, 2211830 )); pts.push_back(Point(11336397, 2268796 )); pts.push_back(Point(11292796, 2312397 )); pts.push_back(Point(11235830, 2335993 )); pts.push_back(Point(11174169, 2335993 )); pts.push_back(Point(11117203, 2312397 )); pts.push_back(Point(11073602, 2268796 )); pts.push_back(Point(11050006, 2211830 )); pts.push_back(Point(11048760, 2204730 )); pts.push_back(Point(11048200, 2201000 )); pts.push_back(Point(10461220, 1614020 )); pts.push_back(Point( 5647400, 1614020 )); pts.push_back(Point( 5642912, 1614461 )); pts.push_back(Point( 5634621, 1617896 )); pts.push_back(Point( 5628276, 1624241 )); pts.push_back(Point( 5624841, 1632532 )); pts.push_back(Point( 5624841, 1641507 )); pts.push_back(Point( 5628276, 1649798 )); pts.push_back(Point( 5631130, 1653280 )); pts.push_back(Point( 5688490, 1710640 )); pts.push_back(Point( 9722350, 1710640 )); pts.push_back(Point(10034620, 2022900 )); pts.push_back(Point(10039200, 2023030 )); pts.push_back(Point(10065830, 2026006 )); pts.push_back(Point(10122796, 2049602 )); pts.push_back(Point(10166397, 2093203 )); pts.push_back(Point(10189993, 2150169 )); pts.push_back(Point(10189993, 2211830 )); pts.push_back(Point(10166397, 2268796 )); pts.push_back(Point(10158620, 2279450 )); pts.push_back(Point(10158620, 2404900 )); pts.push_back(Point(10548950, 2795240 )); pts.push_back(Point(15586950, 2795240 )); pts.push_back(Point(15904620, 3112900 )); pts.push_back(Point(15909200, 3113030 )); pts.push_back(Point(15935830, 3116006 )); pts.push_back(Point(15992796, 3139602 )); pts.push_back(Point(16036397, 3183203 )); pts.push_back(Point(16059993, 3240169 )); pts.push_back(Point(16059993, 3301830 )); pts.push_back(Point(16036397, 3358796 )); pts.push_back(Point(15992796, 3402397 )); pts.push_back(Point(15935830, 3425993 )); pts.push_back(Point(15874169, 3425993 )); pts.push_back(Point(15817203, 3402397 )); pts.push_back(Point(15773602, 3358796 )); pts.push_back(Point(15750006, 3301830 )); pts.push_back(Point(15747030, 3275200 )); pts.push_back(Point(15746900, 3270620 )); pts.push_back(Point(15494570, 3018280 )); pts.push_back(Point(14675510, 3018280 )); pts.push_back(Point(14671032, 3018721 )); pts.push_back(Point(14662741, 3022156 )); pts.push_back(Point(14656396, 3028501 )); pts.push_back(Point(14652961, 3036792 )); pts.push_back(Point(14652961, 3045767 )); pts.push_back(Point(14656396, 3054058 )); pts.push_back(Point(14659260, 3057540 )); pts.push_back(Point(14714620, 3112900 )); pts.push_back(Point(14719200, 3113030 )); pts.push_back(Point(14745830, 3116006 )); pts.push_back(Point(14802796, 3139602 )); pts.push_back(Point(14846397, 3183203 )); pts.push_back(Point(14869993, 3240169 )); pts.push_back(Point(14869993, 3301830 )); pts.push_back(Point(14846397, 3358796 )); pts.push_back(Point(14802796, 3402397 )); pts.push_back(Point(14745830, 3425993 )); pts.push_back(Point(14684169, 3425993 )); pts.push_back(Point(14627203, 3402397 )); pts.push_back(Point(14583602, 3358796 )); pts.push_back(Point(14560006, 3301830 )); pts.push_back(Point(14557030, 3275200 )); pts.push_back(Point(14556900, 3270620 )); pts.push_back(Point(14370700, 3084410 )); pts.push_back(Point(13702830, 3084410 )); pts.push_back(Point(13702830, 3263160 )); pts.push_back(Point(13700003, 3302210 )); pts.push_back(Point(13676407, 3359176 )); pts.push_back(Point(13632806, 3402777 )); pts.push_back(Point(13575840, 3426373 )); pts.push_back(Point(13514179, 3426373 )); pts.push_back(Point(13457213, 3402777 )); pts.push_back(Point(13413612, 3359176 )); pts.push_back(Point(13390016, 3302210 )); pts.push_back(Point(13387030, 3275200 )); pts.push_back(Point(13386900, 3270620 )); pts.push_back(Point(13266840, 3150550 )); pts.push_back(Point(12532920, 3150550 )); pts.push_back(Point(12532920, 3264990 )); pts.push_back(Point(12529993, 3301820 )); pts.push_back(Point(12506397, 3358786 )); pts.push_back(Point(12462796, 3402387 )); pts.push_back(Point(12405830, 3425983 )); pts.push_back(Point(12344169, 3425983 )); pts.push_back(Point(12287203, 3402387 )); pts.push_back(Point(12243602, 3358786 )); pts.push_back(Point(12220006, 3301820 )); pts.push_back(Point(12217030, 3275200 )); pts.push_back(Point(12216900, 3270620 )); pts.push_back(Point(12157460, 3211170 )); pts.push_back(Point(11362030, 3211170 )); pts.push_back(Point(11360250, 3220520 )); pts.push_back(Point(11359993, 3221830 )); pts.push_back(Point(11336397, 3278796 )); pts.push_back(Point(11292796, 3322397 )); pts.push_back(Point(11235830, 3345993 )); pts.push_back(Point(11174169, 3345993 )); pts.push_back(Point(11117203, 3322397 )); pts.push_back(Point(11096270, 3305670 )); pts.push_back(Point(11092940, 3302520 )); pts.push_back(Point(10680760, 3302520 )); pts.push_back(Point(10676272, 3302961 )); pts.push_back(Point(10667981, 3306396 )); pts.push_back(Point(10661636, 3312741 )); pts.push_back(Point(10658201, 3321032 )); pts.push_back(Point(10658201, 3330007 )); pts.push_back(Point(10661636, 3338298 )); pts.push_back(Point(10664500, 3341780 )); pts.push_back(Point(11264260, 3941550 )); pts.push_back(Point(15643260, 3941550 )); pts.push_back(Point(15904620, 4202900 )); pts.push_back(Point(15909200, 4203030 )); pts.push_back(Point(15935830, 4206006 )); pts.push_back(Point(15992796, 4229602 )); pts.push_back(Point(16036397, 4273203 )); pts.push_back(Point(16059993, 4330169 )); pts.push_back(Point(16059993, 4391830 )); pts.push_back(Point(16036397, 4448796 )); pts.push_back(Point(15992796, 4492397 )); pts.push_back(Point(15935830, 4515993 )); pts.push_back(Point(15874169, 4515993 )); pts.push_back(Point(15817203, 4492397 )); pts.push_back(Point(15773602, 4448796 )); pts.push_back(Point(15750006, 4391830 )); pts.push_back(Point(15747030, 4365200 )); pts.push_back(Point(15746900, 4360620 )); pts.push_back(Point(15550880, 4164590 )); pts.push_back(Point(14825070, 4164590 )); pts.push_back(Point(14825070, 4247610 )); pts.push_back(Point(14846397, 4273213 )); pts.push_back(Point(14869993, 4330179 )); pts.push_back(Point(14869993, 4391840 )); pts.push_back(Point(14846397, 4448806 )); pts.push_back(Point(14802796, 4492407 )); pts.push_back(Point(14745830, 4516003 )); pts.push_back(Point(14684169, 4516003 )); pts.push_back(Point(14627203, 4492407 )); pts.push_back(Point(14583602, 4448806 )); pts.push_back(Point(14560006, 4391840 )); pts.push_back(Point(14557030, 4365200 )); pts.push_back(Point(14556900, 4360620 )); pts.push_back(Point(14432520, 4236230 )); pts.push_back(Point(13702830, 4236230 )); pts.push_back(Point(13702830, 4352930 )); pts.push_back(Point(13699993, 4391750 )); pts.push_back(Point(13676397, 4448716 )); pts.push_back(Point(13632796, 4492317 )); pts.push_back(Point(13575830, 4515913 )); pts.push_back(Point(13514169, 4515913 )); pts.push_back(Point(13457203, 4492317 )); pts.push_back(Point(13413602, 4448716 )); pts.push_back(Point(13390006, 4391750 )); pts.push_back(Point(13387030, 4365200 )); pts.push_back(Point(13386900, 4360620 )); pts.push_back(Point(13334170, 4307880 )); pts.push_back(Point(12532990, 4307880 )); pts.push_back(Point(12532990, 4357550 )); pts.push_back(Point(12529993, 4391760 )); pts.push_back(Point(12506397, 4448726 )); pts.push_back(Point(12462796, 4492327 )); pts.push_back(Point(12405830, 4515923 )); pts.push_back(Point(12344169, 4515923 )); pts.push_back(Point(12287203, 4492327 )); pts.push_back(Point(12243602, 4448726 )); pts.push_back(Point(12220006, 4391760 )); pts.push_back(Point(12217970, 4378710 )); pts.push_back(Point(12216810, 4368500 )); pts.push_back(Point(11363190, 4368500 )); pts.push_back(Point(11362030, 4378710 )); pts.push_back(Point(11359983, 4391828 )); pts.push_back(Point(11336388, 4448791 )); pts.push_back(Point(11292791, 4492388 )); pts.push_back(Point(11235828, 4515983 )); pts.push_back(Point(11174171, 4515983 )); pts.push_back(Point(11117208, 4492388 )); pts.push_back(Point(11096270, 4475670 )); pts.push_back(Point(11092940, 4472520 )); pts.push_back(Point(11057750, 4472520 )); pts.push_back(Point(11053272, 4472961 )); pts.push_back(Point(11044981, 4476396 )); pts.push_back(Point(11038636, 4482741 )); pts.push_back(Point(11035201, 4491032 )); pts.push_back(Point(11035201, 4500007 )); pts.push_back(Point(11038636, 4508298 )); pts.push_back(Point(11041490, 4511780 )); pts.push_back(Point(11573490, 5043780 )); pts.push_back(Point(15655490, 5043780 )); pts.push_back(Point(15904620, 5292900 )); pts.push_back(Point(15909200, 5293030 )); pts.push_back(Point(15935830, 5296006 )); pts.push_back(Point(15992796, 5319602 )); pts.push_back(Point(16036397, 5363203 )); pts.push_back(Point(16059993, 5420169 )); pts.push_back(Point(16059993, 5481830 )); pts.push_back(Point(16036397, 5538796 )); pts.push_back(Point(15992796, 5582397 )); pts.push_back(Point(15935830, 5605993 )); pts.push_back(Point(15874169, 5605993 )); pts.push_back(Point(15817203, 5582397 )); pts.push_back(Point(15773602, 5538796 )); pts.push_back(Point(15750006, 5481830 )); pts.push_back(Point(15747030, 5455200 )); pts.push_back(Point(15746900, 5450620 )); pts.push_back(Point(15563110, 5266820 )); pts.push_back(Point(14857380, 5266820 )); pts.push_back(Point(14857380, 5382430 )); pts.push_back(Point(14869993, 5420179 )); pts.push_back(Point(14869993, 5481840 )); pts.push_back(Point(14846397, 5538806 )); pts.push_back(Point(14802796, 5582407 )); pts.push_back(Point(14745830, 5606003 )); pts.push_back(Point(14684169, 5606003 )); pts.push_back(Point(14627203, 5582407 )); pts.push_back(Point(14583602, 5538806 )); pts.push_back(Point(14560006, 5481840 )); pts.push_back(Point(14557030, 5455200 )); pts.push_back(Point(14556900, 5450620 )); pts.push_back(Point(14444750, 5338460 )); pts.push_back(Point(13702890, 5338460 )); pts.push_back(Point(13702890, 5364400 )); pts.push_back(Point(13699993, 5401800 )); pts.push_back(Point(13676397, 5458766 )); pts.push_back(Point(13632796, 5502367 )); pts.push_back(Point(13575830, 5525963 )); pts.push_back(Point(13514169, 5525963 )); pts.push_back(Point(13457203, 5502367 )); pts.push_back(Point(13413602, 5458766 )); pts.push_back(Point(13390006, 5401800 )); pts.push_back(Point(13389230, 5397620 )); pts.push_back(Point(13387590, 5388060 )); pts.push_back(Point(12532960, 5388060 )); pts.push_back(Point(12532960, 5446220 )); pts.push_back(Point(12529993, 5481820 )); pts.push_back(Point(12506397, 5538786 )); pts.push_back(Point(12462796, 5582387 )); pts.push_back(Point(12405830, 5605983 )); pts.push_back(Point(12344169, 5605983 )); pts.push_back(Point(12287203, 5582387 )); pts.push_back(Point(12266270, 5565670 )); pts.push_back(Point(12262940, 5562520 )); pts.push_back(Point(11737750, 5562520 )); pts.push_back(Point(11733272, 5562961 )); pts.push_back(Point(11724981, 5566396 )); pts.push_back(Point(11718636, 5572741 )); pts.push_back(Point(11715201, 5581032 )); pts.push_back(Point(11715201, 5590007 )); pts.push_back(Point(11718636, 5598298 )); pts.push_back(Point(11721500, 5601780 )); pts.push_back(Point(12287760, 6168050 )); pts.push_back(Point(15689760, 6168050 )); pts.push_back(Point(15904620, 6382900 )); pts.push_back(Point(15909200, 6383030 )); pts.push_back(Point(15935830, 6386006 )); pts.push_back(Point(15992796, 6409602 )); pts.push_back(Point(16036397, 6453203 )); pts.push_back(Point(16059993, 6510169 )); pts.push_back(Point(16059993, 6571830 )); pts.push_back(Point(16036397, 6628796 )); pts.push_back(Point(15992796, 6672397 )); pts.push_back(Point(15935830, 6695993 )); pts.push_back(Point(15874169, 6695993 )); pts.push_back(Point(15817203, 6672397 )); pts.push_back(Point(15773602, 6628796 )); pts.push_back(Point(15750006, 6571830 )); pts.push_back(Point(15747030, 6545200 )); pts.push_back(Point(15746900, 6540620 )); pts.push_back(Point(15597380, 6391090 )); pts.push_back(Point(14858060, 6391090 )); pts.push_back(Point(14858060, 6473860 )); pts.push_back(Point(14869993, 6510179 )); pts.push_back(Point(14869993, 6571840 )); pts.push_back(Point(14846397, 6628806 )); pts.push_back(Point(14802796, 6672407 )); pts.push_back(Point(14745830, 6696003 )); pts.push_back(Point(14684169, 6696003 )); pts.push_back(Point(14627203, 6672407 )); pts.push_back(Point(14583602, 6628806 )); pts.push_back(Point(14560006, 6571840 )); pts.push_back(Point(14557030, 6545200 )); pts.push_back(Point(14556900, 6540620 )); pts.push_back(Point(14479020, 6462730 )); pts.push_back(Point(13702990, 6462730 )); pts.push_back(Point(13702990, 6537170 )); pts.push_back(Point(13700003, 6571840 )); pts.push_back(Point(13676407, 6628806 )); pts.push_back(Point(13632806, 6672407 )); pts.push_back(Point(13575840, 6696003 )); pts.push_back(Point(13514179, 6696003 )); pts.push_back(Point(13457213, 6672407 )); pts.push_back(Point(13413612, 6628806 )); pts.push_back(Point(13390016, 6571840 )); pts.push_back(Point(13387040, 6545550 )); pts.push_back(Point(13386710, 6534380 )); pts.push_back(Point(12533290, 6534380 )); pts.push_back(Point(12532960, 6545550 )); pts.push_back(Point(12529983, 6571828 )); pts.push_back(Point(12506388, 6628791 )); pts.push_back(Point(12462791, 6672388 )); pts.push_back(Point(12405828, 6695983 )); pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 )); pts.push_back(Point(12266270, 6655670 )); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); result.clear(); si.merge(result); si.verify1(); print(stdcout, si.pmd) << "\n"; if(!result.empty()) { psd = (*(result.begin())).second; stdcout << psd << "\n"; std::vector<Point> outpts; for(typename polygon_set_data<Unit>::iterator_type itr = psd.begin(); itr != psd.end(); ++itr) { outpts.push_back((*itr).first.first); outpts.push_back((*itr).first.second); } polygon_sort(outpts.begin(), outpts.end()); for(std::size_t i = 0; i < outpts.size(); i+=2) { if(outpts[i] != outpts[i+1]) { stdcout << "Polygon set not a closed figure\n"; stdcout << i << "\n"; stdcout << outpts[i] << " " << outpts[i+1] << "\n"; return 0; } } polys.clear(); psd.get(polys); if(polys.size() == 0) { stdcout << "fail merge 10\n"; return false; } stdcout << (polys[0]) << "\n"; } for(unsigned int i = 0; i < 10; ++i) { stdcout << "random case # " << i << "\n"; si.clear(); pts.clear(); pts.push_back(Point(rand()%9-4, rand()%9-4)); pts.push_back(Point(rand()%9-4, rand()%9-4)); pts.push_back(Point(rand()%9-4, rand()%9-4)); polygon_data<Unit> poly1; poly1.set(pts.begin(), pts.end()); stdcout << poly1 << "\n"; si.insert(poly1, 444); pts.clear(); pts.push_back(Point(rand()%9-4, rand()%9-4)); pts.push_back(Point(rand()%9-4, rand()%9-4)); pts.push_back(Point(rand()%9-4, rand()%9-4)); polygon_data<Unit> poly2; poly2.set(pts.begin(), pts.end()); stdcout << poly2 << "\n"; si.insert(poly2, 444); result.clear(); si.merge(result); print(stdcout, si.pmd) << "\n"; if(!result.empty()) { psd = (*(result.begin())).second; stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() == 0) { si.clear(); si.insert(poly1, 333); result.clear(); si.merge(result); psd = (*(result.begin())).second; std::vector<polygon_data<Unit> > polys1; psd.get(polys1); si.clear(); si.insert(poly2, 333); result.clear(); si.merge(result); psd = (*(result.begin())).second; std::vector<polygon_data<Unit> > polys2; psd.get(polys2); if(!polys1.empty() || !polys2.empty()) { stdcout << "fail random merge " << i << "\n"; return false; } } } if(!polys.empty()) stdcout << polys.size() << ": " << (polys[0]) << "\n"; } return true; } template <typename stream_type> static inline bool check_rectangle_trio(rectangle_data<Unit> rect1, rectangle_data<Unit> rect2, rectangle_data<Unit> rect3, stream_type& stdcout) { property_merge si; std::map<std::set<property_type>, polygon_set_data<Unit> > result; std::vector<polygon_data<Unit> > polys; property_merge_90<property_type, Unit> si90; std::map<std::set<property_type>, polygon_90_set_data<Unit> > result90; std::vector<polygon_data<Unit> > polys90; si.insert(rect1, 111); si90.insert(rect1, 111); stdcout << rect1 << "\n"; si.insert(rect2, 222); si90.insert(rect2, 222); stdcout << rect2 << "\n"; si.insert(rect3, 333); si90.insert(rect3, 333); stdcout << rect3 << "\n"; si.merge(result); si90.merge(result90); if(result.size() != result90.size()) { stdcout << "merge failed with size mismatch\n"; return 0; } typename std::map<std::set<property_type>, polygon_90_set_data<Unit> >::iterator itr90 = result90.begin(); for(typename std::map<std::set<property_type>, polygon_set_data<Unit> >::iterator itr = result.begin(); itr != result.end(); ++itr) { for(typename std::set<property_type>::const_iterator set_itr = (*itr).first.begin(); set_itr != (*itr).first.end(); ++set_itr) { stdcout << (*set_itr) << " "; } stdcout << ") \n"; polygon_set_data<Unit> psd = (*itr).second; polygon_90_set_data<Unit> psd90 = (*itr90).second; polys.clear(); polys90.clear(); psd.get(polys); psd90.get(polys90); if(polys.size() != polys90.size()) { stdcout << "merge failed with polygon count mismatch\n"; stdcout << psd << "\n"; for(std::size_t j = 0; j < polys.size(); ++j) { stdcout << polys[j] << "\n"; } stdcout << "reference\n"; for(std::size_t j = 0; j < polys90.size(); ++j) { stdcout << polys90[j] << "\n"; } return 0; } bool failed = false; for(std::size_t j = 0; j < polys.size(); ++j) { stdcout << polys[j] << "\n"; stdcout << polys90[j] << "\n"; #ifdef BOOST_POLYGON_ICC #pragma warning (push) #pragma warning (disable:1572) #endif if(area(polys[j]) != area(polys90[j])) { #ifdef BOOST_POLYGON_ICC #pragma warning (pop) #endif stdcout << "merge failed with area mismatch\n"; failed = true; } } if(failed) return 0; ++itr90; } return true; } template <typename stream_type> static inline bool test_manhattan_intersection(stream_type& stdcout) { rectangle_data<Unit> rect1, rect2, rect3; set_points(rect1, (Point(-1, 2)), (Point(1, 4))); set_points(rect2, (Point(-1, 2)), (Point(2, 3))); set_points(rect3, (Point(-3, 0)), (Point(4, 2))); if(!check_rectangle_trio(rect1, rect2, rect3, stdcout)) { return false; } for(unsigned int i = 0; i < 100; ++i) { property_merge si; std::map<std::set<property_type>, polygon_set_data<Unit> > result; std::vector<polygon_data<Unit> > polys; property_merge_90<property_type, Unit> si90; std::map<std::set<property_type>, polygon_90_set_data<Unit> > result90; std::vector<polygon_data<Unit> > polys90; stdcout << "random case # " << i << "\n"; set_points(rect1, (Point(rand()%9-4, rand()%9-4)), (Point(rand()%9-4, rand()%9-4))); set_points(rect2, (Point(rand()%9-4, rand()%9-4)), (Point(rand()%9-4, rand()%9-4))); set_points(rect3, (Point(rand()%9-4, rand()%9-4)), (Point(rand()%9-4, rand()%9-4))); if(!check_rectangle_trio(rect1, rect2, rect3, stdcout)) { return false; } } return true; } template <typename stream_type> static inline bool test_intersection(stream_type& stdcout) { property_merge si; rectangle_data<Unit> rect; xl(rect, 0); yl(rect, 10); xh(rect, 30); yh(rect, 20); si.insert(rect, 333); xl(rect, 10); yl(rect, 0); xh(rect, 20); yh(rect, 30); si.insert(rect, 444); xl(rect, 15); yl(rect, 0); xh(rect, 25); yh(rect, 30); si.insert(rect, 555); std::map<std::set<property_type>, polygon_set_data<Unit> > result; si.merge(result); print(stdcout, si.pmd) << "\n"; for(typename std::map<std::set<property_type>, polygon_set_data<Unit> >::iterator itr = result.begin(); itr != result.end(); ++itr) { stdcout << "( "; for(typename std::set<property_type>::const_iterator set_itr = (*itr).first.begin(); set_itr != (*itr).first.end(); ++set_itr) { stdcout << (*set_itr) << " "; } stdcout << ") \n"; polygon_set_data<Unit> psd = (*itr).second; stdcout << psd << "\n"; std::vector<polygon_data<Unit> > polys; psd.get(polys); for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << "\n"; } } std::vector<Point> pts; std::vector<polygon_data<Unit> > polys; for(unsigned int i = 0; i < 10; ++i) { property_merge si2; stdcout << "random case # " << i << "\n"; si.clear(); pts.clear(); pts.push_back(Point(rand()%9-4, rand()%9-4)); pts.push_back(Point(rand()%9-4, rand()%9-4)); pts.push_back(Point(rand()%9-4, rand()%9-4)); polygon_data<Unit> poly1; poly1.set(pts.begin(), pts.end()); stdcout << poly1 << "\n"; si.insert(poly1, 444); si2.insert(poly1, 333); pts.clear(); pts.push_back(Point(rand()%9-4, rand()%9-4)); pts.push_back(Point(rand()%9-4, rand()%9-4)); pts.push_back(Point(rand()%9-4, rand()%9-4)); polygon_data<Unit> poly2; poly2.set(pts.begin(), pts.end()); stdcout << poly2 << "\n"; si.insert(poly2, 444); si2.insert(poly2, 444); pts.clear(); pts.push_back(Point(rand()%9-4, rand()%9-4)); pts.push_back(Point(rand()%9-4, rand()%9-4)); pts.push_back(Point(rand()%9-4, rand()%9-4)); polygon_data<Unit> poly3; poly3.set(pts.begin(), pts.end()); stdcout << poly3 << "\n"; si.insert(poly3, 444); si2.insert(poly3, 555); result.clear(); std::map<std::set<property_type>, polygon_set_data<Unit> > result2; si.merge(result); si2.merge(result2); stdcout << "merged result\n"; for(typename std::map<std::set<property_type>, polygon_set_data<Unit> >::iterator itr = result.begin(); itr != result.end(); ++itr) { stdcout << "( "; for(typename std::set<property_type>::const_iterator set_itr = (*itr).first.begin(); set_itr != (*itr).first.end(); ++set_itr) { stdcout << (*set_itr) << " "; } stdcout << ") \n"; polygon_set_data<Unit> psd = (*itr).second; stdcout << psd << "\n"; std::vector<polygon_data<Unit> > polys2; psd.get(polys2); for(std::size_t ii = 0; ii < polys2.size(); ++ii) { stdcout << polys2[ii] << "\n"; } } stdcout << "intersected pmd\n"; print(stdcout, si2.pmd) << "\n"; stdcout << "intersected result\n"; for(typename std::map<std::set<property_type>, polygon_set_data<Unit> >::iterator itr = result2.begin(); itr != result2.end(); ++itr) { stdcout << "( "; for(typename std::set<property_type>::const_iterator set_itr = (*itr).first.begin(); set_itr != (*itr).first.end(); ++set_itr) { stdcout << (*set_itr) << " "; } stdcout << ") \n"; polygon_set_data<Unit> psd = (*itr).second; stdcout << psd << "\n"; std::vector<polygon_data<Unit> > polys2; psd.get(polys2); for(std::size_t ii = 0; ii < polys2.size(); ++ii) { stdcout << polys2[ii] << "\n"; } } si.clear(); for(typename std::map<std::set<property_type>, polygon_set_data<Unit> >::iterator itr = result2.begin(); itr != result2.end(); ++itr) { polys.clear(); (*itr).second.get(polys); for(std::size_t j = 0; j < polys.size(); ++j) { si.insert(polys[j], 444); } } result2.clear(); si.merge(result2); stdcout << "remerged result\n"; for(typename std::map<std::set<property_type>, polygon_set_data<Unit> >::iterator itr = result2.begin(); itr != result2.end(); ++itr) { stdcout << "( "; for(typename std::set<property_type>::const_iterator set_itr = (*itr).first.begin(); set_itr != (*itr).first.end(); ++set_itr) { stdcout << (*set_itr) << " "; } stdcout << ") \n"; polygon_set_data<Unit> psd = (*itr).second; stdcout << psd << "\n"; std::vector<polygon_data<Unit> > polys2; psd.get(polys2); for(std::size_t ii = 0; ii < polys2.size(); ++ii) { stdcout << polys2[ii] << "\n"; } } std::vector<polygon_data<Unit> > polys2; polys.clear(); (*(result.begin())).second.get(polys); (*(result2.begin())).second.get(polys2); if(!(polys == polys2)) { stdcout << "failed intersection check # " << i << "\n"; return false; } } return true; } }; template <typename Unit> class arbitrary_boolean_op : public scanline_base<Unit> { private: typedef int property_type; typedef typename scanline_base<Unit>::Point Point; //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex //typedef std::pair<Point, Point> half_edge; typedef typename scanline_base<Unit>::half_edge half_edge; //scanline comparator functor typedef typename scanline_base<Unit>::less_half_edge less_half_edge; typedef typename scanline_base<Unit>::less_point less_point; //this data structure assocates a property and count to a half edge typedef std::pair<half_edge, std::pair<property_type, int> > vertex_property; //this data type stores the combination of many half edges typedef std::vector<vertex_property> property_merge_data; //this is the data type used internally to store the combination of property counts at a given location typedef std::vector<std::pair<property_type, int> > property_map; //this data type is used internally to store the combined property data for a given half edge typedef std::pair<half_edge, property_map> vertex_data; property_merge_data pmd; typename scanline_base<Unit>::evalAtXforYPack evalAtXforYPack_; template<typename vertex_data_type> class less_vertex_data { typename scanline_base<Unit>::evalAtXforYPack* pack_; public: less_vertex_data() : pack_() {} less_vertex_data(typename scanline_base<Unit>::evalAtXforYPack* pack) : pack_(pack) {} bool operator()(const vertex_data_type& lvalue, const vertex_data_type& rvalue) const { less_point lp; if(lp(lvalue.first.first, rvalue.first.first)) return true; if(lp(rvalue.first.first, lvalue.first.first)) return false; Unit x = lvalue.first.first.get(HORIZONTAL); int just_before_ = 0; less_half_edge lhe(&x, &just_before_, pack_); return lhe(lvalue.first, rvalue.first); } }; template <typename result_type, typename key_type, int op_type> class boolean_output_functor { public: boolean_output_functor() {} void operator()(result_type& result, const half_edge& edge, const key_type& left, const key_type& right) { typename std::pair<half_edge, int> elem; elem.first = edge; elem.second = 1; if(edge.second < edge.first) elem.second *= -1; if(scanline_base<Unit>::is_vertical(edge)) elem.second *= -1; #ifdef BOOST_POLYGON_MSVC #pragma warning (push) #pragma warning (disable: 4127) #endif if(op_type == 0) { //OR if(!left.empty() && right.empty()) { result.insert_clean(elem); } else if(!right.empty() && left.empty()) { elem.second *= -1; result.insert_clean(elem); } } else if(op_type == 1) { //AND if(left.size() == 2 && right.size() != 2) { result.insert_clean(elem); } else if(right.size() == 2 && left.size() != 2) { elem.second *= -1; result.insert_clean(elem); } } else if(op_type == 2) { //XOR if(left.size() == 1 && right.size() != 1) { result.insert_clean(elem); } else if(right.size() == 1 && left.size() != 1) { elem.second *= -1; result.insert_clean(elem); } } else { //SUBTRACT if(left.size() == 1) { if((*(left.begin())) == 0) { result.insert_clean(elem); } } #ifdef BOOST_POLYGON_MSVC #pragma warning (pop) #endif if(right.size() == 1) { if((*(right.begin())) == 0) { elem.second *= -1; result.insert_clean(elem); } } } } }; inline void sort_property_merge_data() { less_vertex_data<vertex_property> lvd(&evalAtXforYPack_); polygon_sort(pmd.begin(), pmd.end(), lvd); } public: inline arbitrary_boolean_op() : pmd(), evalAtXforYPack_() {} inline arbitrary_boolean_op(const arbitrary_boolean_op& pm) : pmd(pm.pmd), evalAtXforYPack_(pm.evalAtXforYPack_) {} inline arbitrary_boolean_op& operator=(const arbitrary_boolean_op& pm) { pmd = pm.pmd; return *this; } enum BOOLEAN_OP_TYPE { BOOLEAN_OR = 0, BOOLEAN_AND = 1, BOOLEAN_XOR = 2, BOOLEAN_NOT = 3 }; template <typename result_type, typename iT1, typename iT2> inline void execute(result_type& result, iT1 b1, iT1 e1, iT2 b2, iT2 e2, int op) { //intersect data insert(b1, e1, 0); insert(b2, e2, 1); property_merge_data tmp_pmd; //#define BOOST_POLYGON_DEBUG_FILE #ifdef BOOST_POLYGON_DEBUG_FILE std::fstream debug_file; debug_file.open("gtl_debug.txt", std::ios::out); property_merge<Unit, property_type, std::vector<property_type> >::print(debug_file, pmd); debug_file.close(); #endif if(pmd.empty()) return; line_intersection<Unit>::validate_scan(tmp_pmd, pmd.begin(), pmd.end()); pmd.swap(tmp_pmd); sort_property_merge_data(); scanline<Unit, property_type, std::vector<property_type> > sl; if(op == BOOLEAN_OR) { boolean_output_functor<result_type, std::vector<property_type>, 0> bof; sl.scan(result, bof, pmd.begin(), pmd.end()); } else if(op == BOOLEAN_AND) { boolean_output_functor<result_type, std::vector<property_type>, 1> bof; sl.scan(result, bof, pmd.begin(), pmd.end()); } else if(op == BOOLEAN_XOR) { boolean_output_functor<result_type, std::vector<property_type>, 2> bof; sl.scan(result, bof, pmd.begin(), pmd.end()); } else if(op == BOOLEAN_NOT) { boolean_output_functor<result_type, std::vector<property_type>, 3> bof; sl.scan(result, bof, pmd.begin(), pmd.end()); } } inline void clear() {*this = arbitrary_boolean_op();} private: template <typename iT> void insert(iT b, iT e, int id) { for(; b != e; ++b) { pmd.push_back(vertex_property(half_edge((*b).first.first, (*b).first.second), std::pair<property_type, int>(id, (*b).second))); } } }; template <typename Unit, typename stream_type> bool test_arbitrary_boolean_op(stream_type& stdcout) { polygon_set_data<Unit> psd; rectangle_data<Unit> rect; set_points(rect, point_data<Unit>(0, 0), point_data<Unit>(10, 10)); psd.insert(rect); polygon_set_data<Unit> psd2; set_points(rect, point_data<Unit>(5, 5), point_data<Unit>(15, 15)); psd2.insert(rect); std::vector<polygon_data<Unit> > pv; pv.clear(); arbitrary_boolean_op<Unit> abo; polygon_set_data<Unit> psd3; abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op<Unit>::BOOLEAN_OR); psd3.get(pv); for(std::size_t i = 0; i < pv.size(); ++i) { stdcout << pv[i] << "\n"; } pv.clear(); abo.clear(); psd3.clear(); abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op<Unit>::BOOLEAN_AND); psd3.get(pv); for(std::size_t i = 0; i < pv.size(); ++i) { stdcout << pv[i] << "\n"; } pv.clear(); abo.clear(); psd3.clear(); abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op<Unit>::BOOLEAN_XOR); psd3.get(pv); for(std::size_t i = 0; i < pv.size(); ++i) { stdcout << pv[i] << "\n"; } pv.clear(); abo.clear(); psd3.clear(); abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op<Unit>::BOOLEAN_NOT); psd3.get(pv); for(std::size_t i = 0; i < pv.size(); ++i) { stdcout << pv[i] << "\n"; } return true; } template <typename Unit, typename property_type> class arbitrary_connectivity_extraction : public scanline_base<Unit> { private: typedef typename scanline_base<Unit>::Point Point; //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex //typedef std::pair<Point, Point> half_edge; typedef typename scanline_base<Unit>::half_edge half_edge; //scanline comparator functor typedef typename scanline_base<Unit>::less_half_edge less_half_edge; typedef typename scanline_base<Unit>::less_point less_point; //this data structure assocates a property and count to a half edge typedef std::pair<half_edge, std::pair<property_type, int> > vertex_property; //this data type stores the combination of many half edges typedef std::vector<vertex_property> property_merge_data; //this is the data type used internally to store the combination of property counts at a given location typedef std::vector<std::pair<property_type, int> > property_map; //this data type is used internally to store the combined property data for a given half edge typedef std::pair<half_edge, property_map> vertex_data; property_merge_data pmd; typename scanline_base<Unit>::evalAtXforYPack evalAtXforYPack_; template<typename vertex_data_type> class less_vertex_data { typename scanline_base<Unit>::evalAtXforYPack* pack_; public: less_vertex_data() : pack_() {} less_vertex_data(typename scanline_base<Unit>::evalAtXforYPack* pack) : pack_(pack) {} bool operator()(const vertex_data_type& lvalue, const vertex_data_type& rvalue) const { less_point lp; if(lp(lvalue.first.first, rvalue.first.first)) return true; if(lp(rvalue.first.first, lvalue.first.first)) return false; Unit x = lvalue.first.first.get(HORIZONTAL); int just_before_ = 0; less_half_edge lhe(&x, &just_before_, pack_); return lhe(lvalue.first, rvalue.first); } }; template <typename cT> static void process_previous_x(cT& output) { std::map<point_data<Unit>, std::set<property_type> >& y_prop_map = output.first.second; if(y_prop_map.empty()) return; Unit x = output.first.first; for(typename std::map<point_data<Unit>, std::set<property_type> >::iterator itr = y_prop_map.begin(); itr != y_prop_map.end(); ++itr) { if((*itr).first.x() < x) { y_prop_map.erase(y_prop_map.begin(), itr); continue; } for(typename std::set<property_type>::iterator inner_itr = itr->second.begin(); inner_itr != itr->second.end(); ++inner_itr) { std::set<property_type>& output_edges = (*(output.second))[*inner_itr]; typename std::set<property_type>::iterator inner_inner_itr = inner_itr; ++inner_inner_itr; for( ; inner_inner_itr != itr->second.end(); ++inner_inner_itr) { output_edges.insert(output_edges.end(), *inner_inner_itr); std::set<property_type>& output_edges_2 = (*(output.second))[*inner_inner_itr]; output_edges_2.insert(output_edges_2.end(), *inner_itr); } } } } template <typename result_type, typename key_type> class connectivity_extraction_output_functor { public: connectivity_extraction_output_functor() {} void operator()(result_type& result, const half_edge& edge, const key_type& left, const key_type& right) { Unit& x = result.first.first; std::map<point_data<Unit>, std::set<property_type> >& y_prop_map = result.first.second; point_data<Unit> pt = edge.first; if(pt.x() != x) process_previous_x(result); x = pt.x(); std::set<property_type>& output_set = y_prop_map[pt]; { for(typename key_type::const_iterator itr1 = left.begin(); itr1 != left.end(); ++itr1) { output_set.insert(output_set.end(), *itr1); } for(typename key_type::const_iterator itr2 = right.begin(); itr2 != right.end(); ++itr2) { output_set.insert(output_set.end(), *itr2); } } std::set<property_type>& output_set2 = y_prop_map[edge.second]; for(typename key_type::const_iterator itr1 = left.begin(); itr1 != left.end(); ++itr1) { output_set2.insert(output_set2.end(), *itr1); } for(typename key_type::const_iterator itr2 = right.begin(); itr2 != right.end(); ++itr2) { output_set2.insert(output_set2.end(), *itr2); } } }; inline void sort_property_merge_data() { less_vertex_data<vertex_property> lvd(&evalAtXforYPack_); polygon_sort(pmd.begin(), pmd.end(), lvd); } public: inline arbitrary_connectivity_extraction() : pmd(), evalAtXforYPack_() {} inline arbitrary_connectivity_extraction (const arbitrary_connectivity_extraction& pm) : pmd(pm.pmd), evalAtXforYPack_(pm.evalAtXforYPack_) {} inline arbitrary_connectivity_extraction& operator= (const arbitrary_connectivity_extraction& pm) { pmd = pm.pmd; return *this; } template <typename result_type> inline void execute(result_type& result) { //intersect data property_merge_data tmp_pmd; line_intersection<Unit>::validate_scan(tmp_pmd, pmd.begin(), pmd.end()); pmd.swap(tmp_pmd); sort_property_merge_data(); scanline<Unit, property_type, std::vector<property_type> > sl; std::pair<std::pair<Unit, std::map<point_data<Unit>, std::set<property_type> > >, result_type*> output (std::make_pair(std::make_pair((std::numeric_limits<Unit>::max)(), std::map<point_data<Unit>, std::set<property_type> >()), &result)); connectivity_extraction_output_functor<std::pair<std::pair<Unit, std::map<point_data<Unit>, std::set<property_type> > >, result_type*>, std::vector<property_type> > ceof; sl.scan(output, ceof, pmd.begin(), pmd.end()); process_previous_x(output); } inline void clear() {*this = arbitrary_connectivity_extraction();} template <typename iT> void populateTouchSetData(iT begin, iT end, property_type property) { for( ; begin != end; ++begin) { pmd.push_back(vertex_property(half_edge((*begin).first.first, (*begin).first.second), std::pair<property_type, int>(property, (*begin).second))); } } }; } } #endif detail/voronoi_ctypes.hpp 0000644 00000041560 15125572616 0011621 0 ustar 00 // Boost.Polygon library detail/voronoi_ctypes.hpp header file // Copyright Andrii Sydorchuk 2010-2012. // Distributed under 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) // See http://www.boost.org for updates, documentation, and revision history. #ifndef BOOST_POLYGON_DETAIL_VORONOI_CTYPES #define BOOST_POLYGON_DETAIL_VORONOI_CTYPES #include <boost/cstdint.hpp> #include <algorithm> #include <cmath> #include <cstring> #include <utility> #include <vector> namespace boost { namespace polygon { namespace detail { typedef boost::int32_t int32; typedef boost::int64_t int64; typedef boost::uint32_t uint32; typedef boost::uint64_t uint64; typedef double fpt64; // If two floating-point numbers in the same format are ordered (x < y), // then they are ordered the same way when their bits are reinterpreted as // sign-magnitude integers. Values are considered to be almost equal if // their integer bits reinterpretations differ in not more than maxUlps units. template <typename _fpt> struct ulp_comparison; template <> struct ulp_comparison<fpt64> { enum Result { LESS = -1, EQUAL = 0, MORE = 1 }; Result operator()(fpt64 a, fpt64 b, unsigned int maxUlps) const { uint64 ll_a, ll_b; // Reinterpret double bits as 64-bit signed integer. std::memcpy(&ll_a, &a, sizeof(fpt64)); std::memcpy(&ll_b, &b, sizeof(fpt64)); // Positive 0.0 is integer zero. Negative 0.0 is 0x8000000000000000. // Map negative zero to an integer zero representation - making it // identical to positive zero - the smallest negative number is // represented by negative one, and downwards from there. if (ll_a < 0x8000000000000000ULL) ll_a = 0x8000000000000000ULL - ll_a; if (ll_b < 0x8000000000000000ULL) ll_b = 0x8000000000000000ULL - ll_b; // Compare 64-bit signed integer representations of input values. // Difference in 1 Ulp is equivalent to a relative error of between // 1/4,000,000,000,000,000 and 1/8,000,000,000,000,000. if (ll_a > ll_b) return (ll_a - ll_b <= maxUlps) ? EQUAL : LESS; return (ll_b - ll_a <= maxUlps) ? EQUAL : MORE; } }; template <typename _fpt> struct extened_exponent_fpt_traits; template <> struct extened_exponent_fpt_traits<fpt64> { public: typedef int exp_type; enum { MAX_SIGNIFICANT_EXP_DIF = 54 }; }; // Floating point type wrapper. Allows to extend exponent boundaries to the // integer type range. This class does not handle division by zero, subnormal // numbers or NaNs. template <typename _fpt, typename _traits = extened_exponent_fpt_traits<_fpt> > class extended_exponent_fpt { public: typedef _fpt fpt_type; typedef typename _traits::exp_type exp_type; explicit extended_exponent_fpt(fpt_type val) { val_ = std::frexp(val, &exp_); } extended_exponent_fpt(fpt_type val, exp_type exp) { val_ = std::frexp(val, &exp_); exp_ += exp; } bool is_pos() const { return val_ > 0; } bool is_neg() const { return val_ < 0; } bool is_zero() const { return val_ == 0; } extended_exponent_fpt operator-() const { return extended_exponent_fpt(-val_, exp_); } extended_exponent_fpt operator+(const extended_exponent_fpt& that) const { if (this->val_ == 0.0 || that.exp_ > this->exp_ + _traits::MAX_SIGNIFICANT_EXP_DIF) { return that; } if (that.val_ == 0.0 || this->exp_ > that.exp_ + _traits::MAX_SIGNIFICANT_EXP_DIF) { return *this; } if (this->exp_ >= that.exp_) { exp_type exp_dif = this->exp_ - that.exp_; fpt_type val = std::ldexp(this->val_, exp_dif) + that.val_; return extended_exponent_fpt(val, that.exp_); } else { exp_type exp_dif = that.exp_ - this->exp_; fpt_type val = std::ldexp(that.val_, exp_dif) + this->val_; return extended_exponent_fpt(val, this->exp_); } } extended_exponent_fpt operator-(const extended_exponent_fpt& that) const { if (this->val_ == 0.0 || that.exp_ > this->exp_ + _traits::MAX_SIGNIFICANT_EXP_DIF) { return extended_exponent_fpt(-that.val_, that.exp_); } if (that.val_ == 0.0 || this->exp_ > that.exp_ + _traits::MAX_SIGNIFICANT_EXP_DIF) { return *this; } if (this->exp_ >= that.exp_) { exp_type exp_dif = this->exp_ - that.exp_; fpt_type val = std::ldexp(this->val_, exp_dif) - that.val_; return extended_exponent_fpt(val, that.exp_); } else { exp_type exp_dif = that.exp_ - this->exp_; fpt_type val = std::ldexp(-that.val_, exp_dif) + this->val_; return extended_exponent_fpt(val, this->exp_); } } extended_exponent_fpt operator*(const extended_exponent_fpt& that) const { fpt_type val = this->val_ * that.val_; exp_type exp = this->exp_ + that.exp_; return extended_exponent_fpt(val, exp); } extended_exponent_fpt operator/(const extended_exponent_fpt& that) const { fpt_type val = this->val_ / that.val_; exp_type exp = this->exp_ - that.exp_; return extended_exponent_fpt(val, exp); } extended_exponent_fpt& operator+=(const extended_exponent_fpt& that) { return *this = *this + that; } extended_exponent_fpt& operator-=(const extended_exponent_fpt& that) { return *this = *this - that; } extended_exponent_fpt& operator*=(const extended_exponent_fpt& that) { return *this = *this * that; } extended_exponent_fpt& operator/=(const extended_exponent_fpt& that) { return *this = *this / that; } extended_exponent_fpt sqrt() const { fpt_type val = val_; exp_type exp = exp_; if (exp & 1) { val *= 2.0; --exp; } return extended_exponent_fpt(std::sqrt(val), exp >> 1); } fpt_type d() const { return std::ldexp(val_, exp_); } private: fpt_type val_; exp_type exp_; }; typedef extended_exponent_fpt<double> efpt64; template <typename _fpt> extended_exponent_fpt<_fpt> get_sqrt(const extended_exponent_fpt<_fpt>& that) { return that.sqrt(); } template <typename _fpt> bool is_pos(const extended_exponent_fpt<_fpt>& that) { return that.is_pos(); } template <typename _fpt> bool is_neg(const extended_exponent_fpt<_fpt>& that) { return that.is_neg(); } template <typename _fpt> bool is_zero(const extended_exponent_fpt<_fpt>& that) { return that.is_zero(); } // Very efficient stack allocated big integer class. // Supports next set of arithmetic operations: +, -, *. template<std::size_t N> class extended_int { public: extended_int() {} extended_int(int32 that) { if (that > 0) { this->chunks_[0] = that; this->count_ = 1; } else if (that < 0) { this->chunks_[0] = -that; this->count_ = -1; } else { this->count_ = 0; } } extended_int(int64 that) { if (that > 0) { this->chunks_[0] = static_cast<uint32>(that); this->chunks_[1] = that >> 32; this->count_ = this->chunks_[1] ? 2 : 1; } else if (that < 0) { that = -that; this->chunks_[0] = static_cast<uint32>(that); this->chunks_[1] = that >> 32; this->count_ = this->chunks_[1] ? -2 : -1; } else { this->count_ = 0; } } extended_int(const std::vector<uint32>& chunks, bool plus = true) { this->count_ = static_cast<int32>((std::min)(N, chunks.size())); for (int i = 0; i < this->count_; ++i) this->chunks_[i] = chunks[chunks.size() - i - 1]; if (!plus) this->count_ = -this->count_; } template<std::size_t M> extended_int(const extended_int<M>& that) { this->count_ = that.count(); std::memcpy(this->chunks_, that.chunks(), that.size() * sizeof(uint32)); } extended_int& operator=(int32 that) { if (that > 0) { this->chunks_[0] = that; this->count_ = 1; } else if (that < 0) { this->chunks_[0] = -that; this->count_ = -1; } else { this->count_ = 0; } return *this; } extended_int& operator=(int64 that) { if (that > 0) { this->chunks_[0] = static_cast<uint32>(that); this->chunks_[1] = that >> 32; this->count_ = this->chunks_[1] ? 2 : 1; } else if (that < 0) { that = -that; this->chunks_[0] = static_cast<uint32>(that); this->chunks_[1] = that >> 32; this->count_ = this->chunks_[1] ? -2 : -1; } else { this->count_ = 0; } return *this; } template<std::size_t M> extended_int& operator=(const extended_int<M>& that) { this->count_ = that.count(); std::memcpy(this->chunks_, that.chunks(), that.size() * sizeof(uint32)); return *this; } bool is_pos() const { return this->count_ > 0; } bool is_neg() const { return this->count_ < 0; } bool is_zero() const { return this->count_ == 0; } bool operator==(const extended_int& that) const { if (this->count_ != that.count()) return false; for (std::size_t i = 0; i < this->size(); ++i) if (this->chunks_[i] != that.chunks()[i]) return false; return true; } bool operator!=(const extended_int& that) const { return !(*this == that); } bool operator<(const extended_int& that) const { if (this->count_ != that.count()) return this->count_ < that.count(); std::size_t i = this->size(); if (!i) return false; do { --i; if (this->chunks_[i] != that.chunks()[i]) return (this->chunks_[i] < that.chunks()[i]) ^ (this->count_ < 0); } while (i); return false; } bool operator>(const extended_int& that) const { return that < *this; } bool operator<=(const extended_int& that) const { return !(that < *this); } bool operator>=(const extended_int& that) const { return !(*this < that); } extended_int operator-() const { extended_int ret_val = *this; ret_val.neg(); return ret_val; } void neg() { this->count_ = -this->count_; } extended_int operator+(const extended_int& that) const { extended_int ret_val; ret_val.add(*this, that); return ret_val; } void add(const extended_int& e1, const extended_int& e2) { if (!e1.count()) { *this = e2; return; } if (!e2.count()) { *this = e1; return; } if ((e1.count() > 0) ^ (e2.count() > 0)) { dif(e1.chunks(), e1.size(), e2.chunks(), e2.size()); } else { add(e1.chunks(), e1.size(), e2.chunks(), e2.size()); } if (e1.count() < 0) this->count_ = -this->count_; } extended_int operator-(const extended_int& that) const { extended_int ret_val; ret_val.dif(*this, that); return ret_val; } void dif(const extended_int& e1, const extended_int& e2) { if (!e1.count()) { *this = e2; this->count_ = -this->count_; return; } if (!e2.count()) { *this = e1; return; } if ((e1.count() > 0) ^ (e2.count() > 0)) { add(e1.chunks(), e1.size(), e2.chunks(), e2.size()); } else { dif(e1.chunks(), e1.size(), e2.chunks(), e2.size()); } if (e1.count() < 0) this->count_ = -this->count_; } extended_int operator*(int32 that) const { extended_int temp(that); return (*this) * temp; } extended_int operator*(int64 that) const { extended_int temp(that); return (*this) * temp; } extended_int operator*(const extended_int& that) const { extended_int ret_val; ret_val.mul(*this, that); return ret_val; } void mul(const extended_int& e1, const extended_int& e2) { if (!e1.count() || !e2.count()) { this->count_ = 0; return; } mul(e1.chunks(), e1.size(), e2.chunks(), e2.size()); if ((e1.count() > 0) ^ (e2.count() > 0)) this->count_ = -this->count_; } const uint32* chunks() const { return chunks_; } int32 count() const { return count_; } std::size_t size() const { return (std::abs)(count_); } std::pair<fpt64, int> p() const { std::pair<fpt64, int> ret_val(0, 0); std::size_t sz = this->size(); if (!sz) { return ret_val; } else { if (sz == 1) { ret_val.first = static_cast<fpt64>(this->chunks_[0]); } else if (sz == 2) { ret_val.first = static_cast<fpt64>(this->chunks_[1]) * static_cast<fpt64>(0x100000000LL) + static_cast<fpt64>(this->chunks_[0]); } else { for (std::size_t i = 1; i <= 3; ++i) { ret_val.first *= static_cast<fpt64>(0x100000000LL); ret_val.first += static_cast<fpt64>(this->chunks_[sz - i]); } ret_val.second = static_cast<int>((sz - 3) << 5); } } if (this->count_ < 0) ret_val.first = -ret_val.first; return ret_val; } fpt64 d() const { std::pair<fpt64, int> p = this->p(); return std::ldexp(p.first, p.second); } private: void add(const uint32* c1, std::size_t sz1, const uint32* c2, std::size_t sz2) { if (sz1 < sz2) { add(c2, sz2, c1, sz1); return; } this->count_ = static_cast<int32>(sz1); uint64 temp = 0; for (std::size_t i = 0; i < sz2; ++i) { temp += static_cast<uint64>(c1[i]) + static_cast<uint64>(c2[i]); this->chunks_[i] = static_cast<uint32>(temp); temp >>= 32; } for (std::size_t i = sz2; i < sz1; ++i) { temp += static_cast<uint64>(c1[i]); this->chunks_[i] = static_cast<uint32>(temp); temp >>= 32; } if (temp && (this->count_ != N)) { this->chunks_[this->count_] = static_cast<uint32>(temp); ++this->count_; } } void dif(const uint32* c1, std::size_t sz1, const uint32* c2, std::size_t sz2, bool rec = false) { if (sz1 < sz2) { dif(c2, sz2, c1, sz1, true); this->count_ = -this->count_; return; } else if ((sz1 == sz2) && !rec) { do { --sz1; if (c1[sz1] < c2[sz1]) { ++sz1; dif(c2, sz1, c1, sz1, true); this->count_ = -this->count_; return; } else if (c1[sz1] > c2[sz1]) { ++sz1; break; } } while (sz1); if (!sz1) { this->count_ = 0; return; } sz2 = sz1; } this->count_ = static_cast<int32>(sz1-1); bool flag = false; for (std::size_t i = 0; i < sz2; ++i) { this->chunks_[i] = c1[i] - c2[i] - (flag?1:0); flag = (c1[i] < c2[i]) || ((c1[i] == c2[i]) && flag); } for (std::size_t i = sz2; i < sz1; ++i) { this->chunks_[i] = c1[i] - (flag?1:0); flag = !c1[i] && flag; } if (this->chunks_[this->count_]) ++this->count_; } void mul(const uint32* c1, std::size_t sz1, const uint32* c2, std::size_t sz2) { uint64 cur = 0, nxt, tmp; this->count_ = static_cast<int32>((std::min)(N, sz1 + sz2 - 1)); for (std::size_t shift = 0; shift < static_cast<std::size_t>(this->count_); ++shift) { nxt = 0; for (std::size_t first = 0; first <= shift; ++first) { if (first >= sz1) break; std::size_t second = shift - first; if (second >= sz2) continue; tmp = static_cast<uint64>(c1[first]) * static_cast<uint64>(c2[second]); cur += static_cast<uint32>(tmp); nxt += tmp >> 32; } this->chunks_[shift] = static_cast<uint32>(cur); cur = nxt + (cur >> 32); } if (cur && (this->count_ != N)) { this->chunks_[this->count_] = static_cast<uint32>(cur); ++this->count_; } } uint32 chunks_[N]; int32 count_; }; template <std::size_t N> bool is_pos(const extended_int<N>& that) { return that.count() > 0; } template <std::size_t N> bool is_neg(const extended_int<N>& that) { return that.count() < 0; } template <std::size_t N> bool is_zero(const extended_int<N>& that) { return !that.count(); } struct type_converter_fpt { template <typename T> fpt64 operator()(const T& that) const { return static_cast<fpt64>(that); } template <std::size_t N> fpt64 operator()(const extended_int<N>& that) const { return that.d(); } fpt64 operator()(const extended_exponent_fpt<fpt64>& that) const { return that.d(); } }; struct type_converter_efpt { template <std::size_t N> extended_exponent_fpt<fpt64> operator()(const extended_int<N>& that) const { std::pair<fpt64, int> p = that.p(); return extended_exponent_fpt<fpt64>(p.first, p.second); } }; // Voronoi coordinate type traits make it possible to extend algorithm // input coordinate range to any user provided integer type and algorithm // output coordinate range to any ieee-754 like floating point type. template <typename T> struct voronoi_ctype_traits; template <> struct voronoi_ctype_traits<int32> { typedef int32 int_type; typedef int64 int_x2_type; typedef uint64 uint_x2_type; typedef extended_int<64> big_int_type; typedef fpt64 fpt_type; typedef extended_exponent_fpt<fpt_type> efpt_type; typedef ulp_comparison<fpt_type> ulp_cmp_type; typedef type_converter_fpt to_fpt_converter_type; typedef type_converter_efpt to_efpt_converter_type; }; } // detail } // polygon } // boost #endif // BOOST_POLYGON_DETAIL_VORONOI_CTYPES detail/polygon_45_set_view.hpp 0000644 00000041345 15125572616 0012444 0 ustar 00 /* 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_45_SET_VIEW_HPP #define BOOST_POLYGON_POLYGON_45_SET_VIEW_HPP namespace boost { namespace polygon{ template <typename ltype, typename rtype, int op_type> class polygon_45_set_view; template <typename ltype, typename rtype, int op_type> struct polygon_45_set_traits<polygon_45_set_view<ltype, rtype, op_type> > { typedef typename polygon_45_set_view<ltype, rtype, op_type>::coordinate_type coordinate_type; typedef typename polygon_45_set_view<ltype, rtype, op_type>::iterator_type iterator_type; typedef typename polygon_45_set_view<ltype, rtype, op_type>::operator_arg_type operator_arg_type; static inline iterator_type begin(const polygon_45_set_view<ltype, rtype, op_type>& polygon_45_set); static inline iterator_type end(const polygon_45_set_view<ltype, rtype, op_type>& polygon_45_set); template <typename input_iterator_type> static inline void set(polygon_45_set_view<ltype, rtype, op_type>& polygon_45_set, input_iterator_type input_begin, input_iterator_type input_end); static inline bool clean(const polygon_45_set_view<ltype, rtype, op_type>& polygon_45_set); }; template <typename value_type, typename ltype, typename rtype, int op_type> struct compute_45_set_value { static void value(value_type& output_, const ltype& lvalue_, const rtype& rvalue_) { output_.set(polygon_45_set_traits<ltype>::begin(lvalue_), polygon_45_set_traits<ltype>::end(lvalue_)); value_type rinput_; rinput_.set(polygon_45_set_traits<rtype>::begin(rvalue_), polygon_45_set_traits<rtype>::end(rvalue_)); #ifdef BOOST_POLYGON_MSVC #pragma warning (push) #pragma warning (disable: 4127) #endif if(op_type == 0) output_ |= rinput_; else if(op_type == 1) output_ &= rinput_; else if(op_type == 2) output_ ^= rinput_; else output_ -= rinput_; #ifdef BOOST_POLYGON_MSVC #pragma warning (pop) #endif } }; template <typename value_type, typename ltype, typename rcoord, int op_type> struct compute_45_set_value<value_type, ltype, polygon_45_set_data<rcoord>, op_type> { static void value(value_type& output_, const ltype& lvalue_, const polygon_45_set_data<rcoord>& rvalue_) { output_.set(polygon_45_set_traits<ltype>::begin(lvalue_), polygon_45_set_traits<ltype>::end(lvalue_)); #ifdef BOOST_POLYGON_MSVC #pragma warning (push) #pragma warning (disable: 4127) #endif if(op_type == 0) output_ |= rvalue_; else if(op_type == 1) output_ &= rvalue_; else if(op_type == 2) output_ ^= rvalue_; else output_ -= rvalue_; #ifdef BOOST_POLYGON_MSVC #pragma warning (pop) #endif } }; template <typename ltype, typename rtype, int op_type> class polygon_45_set_view { public: typedef typename polygon_45_set_traits<ltype>::coordinate_type coordinate_type; typedef polygon_45_set_data<coordinate_type> value_type; typedef typename value_type::iterator_type iterator_type; typedef polygon_45_set_view operator_arg_type; private: const ltype& lvalue_; const rtype& rvalue_; mutable value_type output_; mutable bool evaluated_; polygon_45_set_view& operator=(const polygon_45_set_view&); public: polygon_45_set_view(const ltype& lvalue, const rtype& rvalue ) : lvalue_(lvalue), rvalue_(rvalue), output_(), evaluated_(false) {} // get iterator to begin vertex data public: const value_type& value() const { if(!evaluated_) { evaluated_ = true; compute_45_set_value<value_type, ltype, rtype, op_type>::value(output_, lvalue_, rvalue_); } return output_; } public: iterator_type begin() const { return value().begin(); } iterator_type end() const { return value().end(); } bool dirty() const { return value().dirty(); } //result of a boolean is clean bool sorted() const { return value().sorted(); } //result of a boolean is sorted // template <typename input_iterator_type> // void set(input_iterator_type input_begin, input_iterator_type input_end, // orientation_2d orient) const { // orient_ = orient; // output_.clear(); // output_.insert(output_.end(), input_begin, input_end); // polygon_sort(output_.begin(), output_.end()); // } }; template <typename ltype, typename rtype, int op_type> typename polygon_45_set_traits<polygon_45_set_view<ltype, rtype, op_type> >::iterator_type polygon_45_set_traits<polygon_45_set_view<ltype, rtype, op_type> >:: begin(const polygon_45_set_view<ltype, rtype, op_type>& polygon_45_set) { return polygon_45_set.begin(); } template <typename ltype, typename rtype, int op_type> typename polygon_45_set_traits<polygon_45_set_view<ltype, rtype, op_type> >::iterator_type polygon_45_set_traits<polygon_45_set_view<ltype, rtype, op_type> >:: end(const polygon_45_set_view<ltype, rtype, op_type>& polygon_45_set) { return polygon_45_set.end(); } template <typename ltype, typename rtype, int op_type> bool polygon_45_set_traits<polygon_45_set_view<ltype, rtype, op_type> >:: clean(const polygon_45_set_view<ltype, rtype, op_type>& polygon_45_set) { return polygon_45_set.value().clean(); } template <typename geometry_type_1, typename geometry_type_2, int op_type> geometry_type_1& self_assignment_boolean_op_45(geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { typedef geometry_type_1 ltype; typedef geometry_type_2 rtype; typedef typename polygon_45_set_traits<ltype>::coordinate_type coordinate_type; typedef polygon_45_set_data<coordinate_type> value_type; value_type output_; value_type rinput_; output_.set(polygon_45_set_traits<ltype>::begin(lvalue_), polygon_45_set_traits<ltype>::end(lvalue_)); rinput_.set(polygon_45_set_traits<rtype>::begin(rvalue_), polygon_45_set_traits<rtype>::end(rvalue_)); #ifdef BOOST_POLYGON_MSVC #pragma warning (push) #pragma warning (disable: 4127) #endif if(op_type == 0) output_ |= rinput_; else if(op_type == 1) output_ &= rinput_; else if(op_type == 2) output_ ^= rinput_; else output_ -= rinput_; #ifdef BOOST_POLYGON_MSVC #pragma warning (pop) #endif polygon_45_set_mutable_traits<geometry_type_1>::set(lvalue_, output_.begin(), output_.end()); return lvalue_; } template <typename concept_type> struct fracture_holes_option_by_type { static const bool value = true; }; template <> struct fracture_holes_option_by_type<polygon_45_with_holes_concept> { static const bool value = false; }; template <> struct fracture_holes_option_by_type<polygon_with_holes_concept> { static const bool value = false; }; template <typename ltype, typename rtype, int op_type> struct geometry_concept<polygon_45_set_view<ltype, rtype, op_type> > { typedef polygon_45_set_concept type; }; namespace operators { struct y_ps45_b : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_4< y_ps45_b, typename is_polygon_45_or_90_set_type<geometry_type_1>::type, typename is_polygon_45_or_90_set_type<geometry_type_2>::type, typename is_either_polygon_45_set_type<geometry_type_1, geometry_type_2>::type>::type, polygon_45_set_view<geometry_type_1, geometry_type_2, 0> >::type operator|(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_45_set_view<geometry_type_1, geometry_type_2, 0> (lvalue, rvalue); } struct y_ps45_p : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_4< y_ps45_p, typename gtl_if<typename is_polygon_45_or_90_set_type<geometry_type_1>::type>::type, typename gtl_if<typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, typename gtl_if<typename is_either_polygon_45_set_type<geometry_type_1, geometry_type_2>::type>::type>::type, polygon_45_set_view<geometry_type_1, geometry_type_2, 0> >::type operator+(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_45_set_view<geometry_type_1, geometry_type_2, 0> (lvalue, rvalue); } struct y_ps45_s : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_4< y_ps45_s, typename is_polygon_45_or_90_set_type<geometry_type_1>::type, typename is_polygon_45_or_90_set_type<geometry_type_2>::type, typename is_either_polygon_45_set_type<geometry_type_1, geometry_type_2>::type>::type, polygon_45_set_view<geometry_type_1, geometry_type_2, 1> >::type operator*(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_45_set_view<geometry_type_1, geometry_type_2, 1> (lvalue, rvalue); } struct y_ps45_a : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_4< y_ps45_a, typename is_polygon_45_or_90_set_type<geometry_type_1>::type, typename is_polygon_45_or_90_set_type<geometry_type_2>::type, typename is_either_polygon_45_set_type<geometry_type_1, geometry_type_2>::type>::type, polygon_45_set_view<geometry_type_1, geometry_type_2, 1> >::type operator&(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_45_set_view<geometry_type_1, geometry_type_2, 1> (lvalue, rvalue); } struct y_ps45_x : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_4< y_ps45_x, typename is_polygon_45_or_90_set_type<geometry_type_1>::type, typename is_polygon_45_or_90_set_type<geometry_type_2>::type, typename is_either_polygon_45_set_type<geometry_type_1, geometry_type_2>::type>::type, polygon_45_set_view<geometry_type_1, geometry_type_2, 2> >::type operator^(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_45_set_view<geometry_type_1, geometry_type_2, 2> (lvalue, rvalue); } struct y_ps45_m : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_4< y_ps45_m, typename gtl_if<typename is_polygon_45_or_90_set_type<geometry_type_1>::type>::type, typename gtl_if<typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, typename gtl_if<typename is_either_polygon_45_set_type<geometry_type_1, geometry_type_2>::type>::type>::type, polygon_45_set_view<geometry_type_1, geometry_type_2, 3> >::type operator-(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_45_set_view<geometry_type_1, geometry_type_2, 3> (lvalue, rvalue); } struct y_ps45_pe : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_4<y_ps45_pe, typename is_mutable_polygon_45_set_type<geometry_type_1>::type, gtl_yes, typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator+=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op_45<geometry_type_1, geometry_type_2, 0>(lvalue, rvalue); } struct y_ps45_be : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3<y_ps45_be, typename is_mutable_polygon_45_set_type<geometry_type_1>::type, typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator|=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op_45<geometry_type_1, geometry_type_2, 0>(lvalue, rvalue); } struct y_ps45_se : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3< y_ps45_se, typename is_mutable_polygon_45_set_type<geometry_type_1>::type, typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator*=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op_45<geometry_type_1, geometry_type_2, 1>(lvalue, rvalue); } struct y_ps45_ae : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3<y_ps45_ae, typename is_mutable_polygon_45_set_type<geometry_type_1>::type, typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator&=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op_45<geometry_type_1, geometry_type_2, 1>(lvalue, rvalue); } struct y_ps45_xe : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3<y_ps45_xe, typename is_mutable_polygon_45_set_type<geometry_type_1>::type, typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator^=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op_45<geometry_type_1, geometry_type_2, 2>(lvalue, rvalue); } struct y_ps45_me : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3<y_ps45_me, typename is_mutable_polygon_45_set_type<geometry_type_1>::type, typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator-=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op_45<geometry_type_1, geometry_type_2, 3>(lvalue, rvalue); } struct y_ps45_rpe : gtl_yes {}; template <typename geometry_type_1, typename coordinate_type_1> typename enable_if< typename gtl_and_3< y_ps45_rpe, typename is_mutable_polygon_45_set_type<geometry_type_1>::type, typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type>::type, geometry_type_1>::type & operator+=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { return resize(lvalue, rvalue); } struct y_ps45_rme : gtl_yes {}; template <typename geometry_type_1, typename coordinate_type_1> typename enable_if< typename gtl_and_3<y_ps45_rme, typename gtl_if<typename is_mutable_polygon_45_set_type<geometry_type_1>::type>::type, typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type>::type, geometry_type_1>::type & operator-=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { return resize(lvalue, -rvalue); } struct y_ps45_rp : gtl_yes {}; template <typename geometry_type_1, typename coordinate_type_1> typename enable_if< typename gtl_and_3<y_ps45_rp, typename gtl_if<typename is_mutable_polygon_45_set_type<geometry_type_1>::type>::type, typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type> ::type, geometry_type_1>::type operator+(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { geometry_type_1 retval(lvalue); retval += rvalue; return retval; } struct y_ps45_rm : gtl_yes {}; template <typename geometry_type_1, typename coordinate_type_1> typename enable_if< typename gtl_and_3<y_ps45_rm, typename gtl_if<typename is_mutable_polygon_45_set_type<geometry_type_1>::type>::type, typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type> ::type, geometry_type_1>::type operator-(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { geometry_type_1 retval(lvalue); retval -= rvalue; return retval; } } } } #endif detail/polygon_90_set_view.hpp 0000644 00000057772 15125572616 0012457 0 ustar 00 /* 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_VIEW_HPP #define BOOST_POLYGON_POLYGON_90_SET_VIEW_HPP namespace boost { namespace polygon{ struct operator_provides_storage {}; struct operator_requires_copy {}; template <typename value_type, typename arg_type> inline void insert_into_view_arg(value_type& dest, const arg_type& arg, orientation_2d orient); template <typename ltype, typename rtype, typename op_type> class polygon_90_set_view; template <typename ltype, typename rtype, typename op_type> struct polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> > { typedef typename polygon_90_set_view<ltype, rtype, op_type>::coordinate_type coordinate_type; typedef typename polygon_90_set_view<ltype, rtype, op_type>::iterator_type iterator_type; typedef typename polygon_90_set_view<ltype, rtype, op_type>::operator_arg_type operator_arg_type; static inline iterator_type begin(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set); static inline iterator_type end(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set); static inline orientation_2d orient(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set); static inline bool clean(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set); static inline bool sorted(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set); }; template <typename value_type, typename ltype, typename rtype, typename op_type> struct compute_90_set_value { static void value(value_type& output_, const ltype& lvalue_, const rtype& rvalue_, orientation_2d orient_) { value_type linput_(orient_); value_type rinput_(orient_); orientation_2d orient_l = polygon_90_set_traits<ltype>::orient(lvalue_); orientation_2d orient_r = polygon_90_set_traits<rtype>::orient(rvalue_); //std::cout << "compute_90_set_value-0 orientations (left, right, out):\t" << orient_l.to_int() // << "," << orient_r.to_int() << "," << orient_.to_int() << std::endl; insert_into_view_arg(linput_, lvalue_, orient_l); insert_into_view_arg(rinput_, rvalue_, orient_r); output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), rinput_.begin(), rinput_.end(), boolean_op::BinaryCount<op_type>()); } }; template <typename value_type, typename lcoord, typename rcoord, typename op_type> struct compute_90_set_value<value_type, polygon_90_set_data<lcoord>, polygon_90_set_data<rcoord>, op_type> { static void value(value_type& output_, const polygon_90_set_data<lcoord>& lvalue_, const polygon_90_set_data<rcoord>& rvalue_, orientation_2d orient_) { orientation_2d orient_l = lvalue_.orient(); orientation_2d orient_r = rvalue_.orient(); value_type linput_(orient_); value_type rinput_(orient_); //std::cout << "compute_90_set_value-1 orientations (left, right, out):\t" << orient_l.to_int() // << "," << orient_r.to_int() << "," << orient_.to_int() << std::endl; if((orient_ == orient_l) && (orient_== orient_r)){ // assume that most of the time this condition is met lvalue_.sort(); rvalue_.sort(); output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount<op_type>()); }else if((orient_ != orient_l) && (orient_!= orient_r)){ // both the orientations are not equal to input // easier way is to ignore the input orientation and use the input data's orientation, but not done so insert_into_view_arg(linput_, lvalue_, orient_l); insert_into_view_arg(rinput_, rvalue_, orient_r); output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), rinput_.begin(), rinput_.end(), boolean_op::BinaryCount<op_type>()); }else if(orient_ != orient_l){ // left hand side orientation is different insert_into_view_arg(linput_, lvalue_, orient_l); rvalue_.sort(); output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount<op_type>()); } else if(orient_ != orient_r){ // right hand side orientation is different insert_into_view_arg(rinput_, rvalue_, orient_r); lvalue_.sort(); output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), rinput_.begin(), rinput_.end(), boolean_op::BinaryCount<op_type>()); } } }; template <typename value_type, typename lcoord, typename rtype, typename op_type> struct compute_90_set_value<value_type, polygon_90_set_data<lcoord>, rtype, op_type> { static void value(value_type& output_, const polygon_90_set_data<lcoord>& lvalue_, const rtype& rvalue_, orientation_2d orient_) { value_type rinput_(orient_); lvalue_.sort(); orientation_2d orient_r = polygon_90_set_traits<rtype>::orient(rvalue_); //std::cout << "compute_90_set_value-2 orientations (right, out):\t" << orient_r.to_int() // << "," << orient_.to_int() << std::endl; insert_into_view_arg(rinput_, rvalue_, orient_r); output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), rinput_.begin(), rinput_.end(), boolean_op::BinaryCount<op_type>()); } }; template <typename value_type, typename ltype, typename rcoord, typename op_type> struct compute_90_set_value<value_type, ltype, polygon_90_set_data<rcoord>, op_type> { static void value(value_type& output_, const ltype& lvalue_, const polygon_90_set_data<rcoord>& rvalue_, orientation_2d orient_) { value_type linput_(orient_); orientation_2d orient_l = polygon_90_set_traits<ltype>::orient(lvalue_); insert_into_view_arg(linput_, lvalue_, orient_l); rvalue_.sort(); //std::cout << "compute_90_set_value-3 orientations (left, out):\t" << orient_l.to_int() // << "," << orient_.to_int() << std::endl; output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount<op_type>()); } }; template <typename ltype, typename rtype, typename op_type> class polygon_90_set_view { public: typedef typename polygon_90_set_traits<ltype>::coordinate_type coordinate_type; typedef polygon_90_set_data<coordinate_type> value_type; typedef typename value_type::iterator_type iterator_type; typedef polygon_90_set_view operator_arg_type; private: const ltype& lvalue_; const rtype& rvalue_; orientation_2d orient_; op_type op_; mutable value_type output_; mutable bool evaluated_; polygon_90_set_view& operator=(const polygon_90_set_view&); public: polygon_90_set_view(const ltype& lvalue, const rtype& rvalue, orientation_2d orient, op_type op) : lvalue_(lvalue), rvalue_(rvalue), orient_(orient), op_(op), output_(orient), evaluated_(false) {} // get iterator to begin vertex data private: const value_type& value() const { if(!evaluated_) { evaluated_ = true; compute_90_set_value<value_type, ltype, rtype, op_type>::value(output_, lvalue_, rvalue_, orient_); } return output_; } public: iterator_type begin() const { return value().begin(); } iterator_type end() const { return value().end(); } orientation_2d orient() const { return orient_; } bool dirty() const { return false; } //result of a boolean is clean bool sorted() const { return true; } //result of a boolean is sorted // template <typename input_iterator_type> // void set(input_iterator_type input_begin, input_iterator_type input_end, // orientation_2d orient) const { // orient_ = orient; // output_.clear(); // output_.insert(output_.end(), input_begin, input_end); // polygon_sort(output_.begin(), output_.end()); // } void sort() const {} //is always sorted }; template <typename ltype, typename rtype, typename op_type> struct geometry_concept<polygon_90_set_view<ltype, rtype, op_type> > { typedef polygon_90_set_concept type; }; template <typename ltype, typename rtype, typename op_type> typename polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >::iterator_type polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >:: begin(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set) { return polygon_set.begin(); } template <typename ltype, typename rtype, typename op_type> typename polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >::iterator_type polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >:: end(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set) { return polygon_set.end(); } // template <typename ltype, typename rtype, typename op_type> // template <typename input_iterator_type> // void polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >:: // set(polygon_90_set_view<ltype, rtype, op_type>& polygon_set, // input_iterator_type input_begin, input_iterator_type input_end, // orientation_2d orient) { // polygon_set.set(input_begin, input_end, orient); // } template <typename ltype, typename rtype, typename op_type> orientation_2d polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >:: orient(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set) { return polygon_set.orient(); } template <typename ltype, typename rtype, typename op_type> bool polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >:: clean(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set) { return !polygon_set.dirty(); } template <typename ltype, typename rtype, typename op_type> bool polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >:: sorted(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set) { return polygon_set.sorted(); } template <typename value_type, typename arg_type> inline void insert_into_view_arg(value_type& dest, const arg_type& arg, orientation_2d orient) { typedef typename polygon_90_set_traits<arg_type>::iterator_type literator; literator itr1, itr2; itr1 = polygon_90_set_traits<arg_type>::begin(arg); itr2 = polygon_90_set_traits<arg_type>::end(arg); dest.insert(itr1, itr2, orient); dest.sort(); } template <typename T> template <typename ltype, typename rtype, typename op_type> inline polygon_90_set_data<T>& polygon_90_set_data<T>::operator=(const polygon_90_set_view<ltype, rtype, op_type>& that) { set(that.begin(), that.end(), that.orient()); dirty_ = false; unsorted_ = false; return *this; } template <typename T> template <typename ltype, typename rtype, typename op_type> inline polygon_90_set_data<T>::polygon_90_set_data(const polygon_90_set_view<ltype, rtype, op_type>& that) : orient_(that.orient()), data_(that.begin(), that.end()), dirty_(false), unsorted_(false) {} template <typename geometry_type_1, typename geometry_type_2> struct self_assign_operator_lvalue { typedef geometry_type_1& type; }; template <typename type_1, typename type_2> struct by_value_binary_operator { typedef type_1 type; }; template <typename geometry_type_1, typename geometry_type_2, typename op_type> geometry_type_1& self_assignment_boolean_op(geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { typedef geometry_type_1 ltype; typedef geometry_type_2 rtype; typedef typename polygon_90_set_traits<ltype>::coordinate_type coordinate_type; typedef polygon_90_set_data<coordinate_type> value_type; orientation_2d orient_ = polygon_90_set_traits<ltype>::orient(lvalue_); //BM: rvalue_ data set may have its own orientation for scanline orientation_2d orient_r = polygon_90_set_traits<rtype>::orient(rvalue_); //std::cout << "self-assignment boolean-op (left, right, out):\t" << orient_.to_int() // << "," << orient_r.to_int() << "," << orient_.to_int() << std::endl; value_type linput_(orient_); // BM: the rinput_ set's (that stores the rvalue_ dataset polygons) scanline orientation is *forced* // to be same as linput value_type rinput_(orient_); //BM: The output dataset's scanline orient is set as equal to first input dataset's (lvalue_) orientation value_type output_(orient_); insert_into_view_arg(linput_, lvalue_, orient_); // BM: The last argument orient_r is the user initialized scanline orientation for rvalue_ data set. // But since rinput (see above) is initialized to scanline orientation consistent with the lvalue_ // data set, this insertion operation will change the incoming rvalue_ dataset's scanline orientation insert_into_view_arg(rinput_, rvalue_, orient_r); // BM: boolean operation and output uses lvalue_ dataset's scanline orientation. output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), rinput_.begin(), rinput_.end(), boolean_op::BinaryCount<op_type>()); polygon_90_set_mutable_traits<geometry_type_1>::set(lvalue_, output_.begin(), output_.end(), orient_); return lvalue_; } namespace operators { struct y_ps90_b : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3< y_ps90_b, typename is_polygon_90_set_type<geometry_type_1>::type, typename is_polygon_90_set_type<geometry_type_2>::type>::type, polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryOr> >::type operator|(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryOr> (lvalue, rvalue, polygon_90_set_traits<geometry_type_1>::orient(lvalue), boolean_op::BinaryOr()); } struct y_ps90_p : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3< y_ps90_p, typename gtl_if<typename is_polygon_90_set_type<geometry_type_1>::type>::type, typename gtl_if<typename is_polygon_90_set_type<geometry_type_2>::type>::type>::type, polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryOr> >::type operator+(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryOr> (lvalue, rvalue, polygon_90_set_traits<geometry_type_1>::orient(lvalue), boolean_op::BinaryOr()); } struct y_ps90_s : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3< y_ps90_s, typename is_polygon_90_set_type<geometry_type_1>::type, typename is_polygon_90_set_type<geometry_type_2>::type>::type, polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryAnd> >::type operator*(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryAnd> (lvalue, rvalue, polygon_90_set_traits<geometry_type_1>::orient(lvalue), boolean_op::BinaryAnd()); } struct y_ps90_a : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3< y_ps90_a, typename is_polygon_90_set_type<geometry_type_1>::type, typename is_polygon_90_set_type<geometry_type_2>::type>::type, polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryAnd> >::type operator&(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryAnd> (lvalue, rvalue, polygon_90_set_traits<geometry_type_1>::orient(lvalue), boolean_op::BinaryAnd()); } struct y_ps90_x : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3< y_ps90_x, typename is_polygon_90_set_type<geometry_type_1>::type, typename is_polygon_90_set_type<geometry_type_2>::type>::type, polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryXor> >::type operator^(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryXor> (lvalue, rvalue, polygon_90_set_traits<geometry_type_1>::orient(lvalue), boolean_op::BinaryXor()); } struct y_ps90_m : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3< y_ps90_m, typename gtl_if<typename is_polygon_90_set_type<geometry_type_1>::type>::type, typename gtl_if<typename is_polygon_90_set_type<geometry_type_2>::type>::type>::type, polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryNot> >::type operator-(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryNot> (lvalue, rvalue, polygon_90_set_traits<geometry_type_1>::orient(lvalue), boolean_op::BinaryNot()); } struct y_ps90_pe : gtl_yes {}; template <typename coordinate_type_1, typename geometry_type_2> typename enable_if< typename gtl_and< y_ps90_pe, typename is_polygon_90_set_type<geometry_type_2>::type>::type, polygon_90_set_data<coordinate_type_1> >::type & operator+=(polygon_90_set_data<coordinate_type_1>& lvalue, const geometry_type_2& rvalue) { lvalue.insert(polygon_90_set_traits<geometry_type_2>::begin(rvalue), polygon_90_set_traits<geometry_type_2>::end(rvalue), polygon_90_set_traits<geometry_type_2>::orient(rvalue)); return lvalue; } struct y_ps90_be : gtl_yes {}; // template <typename coordinate_type_1, typename geometry_type_2> typename enable_if< typename gtl_and< y_ps90_be, typename is_polygon_90_set_type<geometry_type_2>::type>::type, polygon_90_set_data<coordinate_type_1> >::type & operator|=(polygon_90_set_data<coordinate_type_1>& lvalue, const geometry_type_2& rvalue) { return lvalue += rvalue; } struct y_ps90_pe2 : gtl_yes {}; //normal self assignment boolean operations template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3< y_ps90_pe2, typename is_mutable_polygon_90_set_type<geometry_type_1>::type, typename is_polygon_90_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator+=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op<geometry_type_1, geometry_type_2, boolean_op::BinaryOr>(lvalue, rvalue); } struct y_ps90_be2 : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3<y_ps90_be2, typename is_mutable_polygon_90_set_type<geometry_type_1>::type, typename is_polygon_90_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator|=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op<geometry_type_1, geometry_type_2, boolean_op::BinaryOr>(lvalue, rvalue); } struct y_ps90_se : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3<y_ps90_se, typename is_mutable_polygon_90_set_type<geometry_type_1>::type, typename is_polygon_90_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator*=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op<geometry_type_1, geometry_type_2, boolean_op::BinaryAnd>(lvalue, rvalue); } struct y_ps90_ae : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3<y_ps90_ae, typename is_mutable_polygon_90_set_type<geometry_type_1>::type, typename is_polygon_90_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator&=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op<geometry_type_1, geometry_type_2, boolean_op::BinaryAnd>(lvalue, rvalue); } struct y_ps90_xe : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3<y_ps90_xe, typename is_mutable_polygon_90_set_type<geometry_type_1>::type, typename is_polygon_90_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator^=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op<geometry_type_1, geometry_type_2, boolean_op::BinaryXor>(lvalue, rvalue); } struct y_ps90_me : gtl_yes {}; template <typename geometry_type_1, typename geometry_type_2> typename enable_if< typename gtl_and_3< y_ps90_me, typename is_mutable_polygon_90_set_type<geometry_type_1>::type, typename is_polygon_90_set_type<geometry_type_2>::type>::type, geometry_type_1>::type & operator-=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op<geometry_type_1, geometry_type_2, boolean_op::BinaryNot>(lvalue, rvalue); } struct y_ps90_rpe : gtl_yes {}; template <typename geometry_type_1, typename coordinate_type_1> typename enable_if< typename gtl_and_3<y_ps90_rpe, typename is_mutable_polygon_90_set_type<geometry_type_1>::type, typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type>::type, geometry_type_1>::type & operator+=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { return resize(lvalue, rvalue); } struct y_ps90_rme : gtl_yes {}; template <typename geometry_type_1, typename coordinate_type_1> typename enable_if< typename gtl_and_3<y_ps90_rme, typename is_mutable_polygon_90_set_type<geometry_type_1>::type, typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type>::type, geometry_type_1>::type & operator-=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { return resize(lvalue, -rvalue); } struct y_ps90_rp : gtl_yes {}; template <typename geometry_type_1, typename coordinate_type_1> typename enable_if< typename gtl_and_3<y_ps90_rp, typename gtl_if<typename is_mutable_polygon_90_set_type<geometry_type_1>::type>::type, typename gtl_if<typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type>::type>::type, geometry_type_1>::type operator+(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { geometry_type_1 retval(lvalue); retval += rvalue; return retval; } struct y_ps90_rm : gtl_yes {}; template <typename geometry_type_1, typename coordinate_type_1> typename enable_if< typename gtl_and_3<y_ps90_rm, typename gtl_if<typename is_mutable_polygon_90_set_type<geometry_type_1>::type>::type, typename gtl_if<typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type>::type>::type, geometry_type_1>::type operator-(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { geometry_type_1 retval(lvalue); retval -= rvalue; return retval; } } } } #endif detail/property_merge.hpp 0000644 00000055111 15125572616 0011577 0 ustar 00 /* 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_PROPERTY_MERGE_HPP #define BOOST_POLYGON_PROPERTY_MERGE_HPP namespace boost { namespace polygon{ template <typename coordinate_type> class property_merge_point { private: coordinate_type x_, y_; public: inline property_merge_point() : x_(), y_() {} inline property_merge_point(coordinate_type x, coordinate_type y) : x_(x), y_(y) {} //use builtin assign and copy inline bool operator==(const property_merge_point& that) const { return x_ == that.x_ && y_ == that.y_; } inline bool operator!=(const property_merge_point& that) const { return !((*this) == that); } inline bool operator<(const property_merge_point& that) const { if(x_ < that.x_) return true; if(x_ > that.x_) return false; return y_ < that.y_; } inline coordinate_type x() const { return x_; } inline coordinate_type y() const { return y_; } inline void x(coordinate_type value) { x_ = value; } inline void y(coordinate_type value) { y_ = value; } }; template <typename coordinate_type> class property_merge_interval { private: coordinate_type low_, high_; public: inline property_merge_interval() : low_(), high_() {} inline property_merge_interval(coordinate_type low, coordinate_type high) : low_(low), high_(high) {} //use builtin assign and copy inline bool operator==(const property_merge_interval& that) const { return low_ == that.low_ && high_ == that.high_; } inline bool operator!=(const property_merge_interval& that) const { return !((*this) == that); } inline bool operator<(const property_merge_interval& that) const { if(low_ < that.low_) return true; if(low_ > that.low_) return false; return high_ < that.high_; } inline coordinate_type low() const { return low_; } inline coordinate_type high() const { return high_; } inline void low(coordinate_type value) { low_ = value; } inline void high(coordinate_type value) { high_ = value; } }; template <typename coordinate_type, typename property_type, typename polygon_set_type, typename keytype = std::set<property_type> > class merge_scanline { public: //definitions typedef keytype property_set; typedef std::vector<std::pair<property_type, int> > property_map; typedef std::pair<property_merge_point<coordinate_type>, std::pair<property_type, int> > vertex_property; typedef std::pair<property_merge_point<coordinate_type>, property_map> vertex_data; typedef std::vector<vertex_property> property_merge_data; //typedef std::map<property_set, polygon_set_type> Result; typedef std::map<coordinate_type, property_map> scanline_type; typedef typename scanline_type::iterator scanline_iterator; typedef std::pair<property_merge_interval<coordinate_type>, std::pair<property_set, property_set> > edge_property; typedef std::vector<edge_property> edge_property_vector; //static public member functions template <typename iT, typename orientation_2d_type> static inline void populate_property_merge_data(property_merge_data& pmd, iT input_begin, iT input_end, const property_type& property, orientation_2d_type orient) { for( ; input_begin != input_end; ++input_begin) { std::pair<property_merge_point<coordinate_type>, std::pair<property_type, int> > element; if(orient == HORIZONTAL) element.first = property_merge_point<coordinate_type>((*input_begin).second.first, (*input_begin).first); else element.first = property_merge_point<coordinate_type>((*input_begin).first, (*input_begin).second.first); element.second.first = property; element.second.second = (*input_begin).second.second; pmd.push_back(element); } } //public member functions merge_scanline() : output(), scanline(), currentVertex(), tmpVector(), previousY(), countFromBelow(), scanlinePosition() {} merge_scanline(const merge_scanline& that) : output(that.output), scanline(that.scanline), currentVertex(that.currentVertex), tmpVector(that.tmpVector), previousY(that.previousY), countFromBelow(that.countFromBelow), scanlinePosition(that.scanlinePosition) {} merge_scanline& operator=(const merge_scanline& that) { output = that.output; scanline = that.scanline; currentVertex = that.currentVertex; tmpVector = that.tmpVector; previousY = that.previousY; countFromBelow = that.countFromBelow; scanlinePosition = that.scanlinePosition; return *this; } template <typename result_type> inline void perform_merge(result_type& result, property_merge_data& data) { if(data.empty()) return; //sort polygon_sort(data.begin(), data.end(), less_vertex_data<vertex_property>()); //scanline bool firstIteration = true; scanlinePosition = scanline.end(); for(std::size_t i = 0; i < data.size(); ++i) { if(firstIteration) { mergeProperty(currentVertex.second, data[i].second); currentVertex.first = data[i].first; firstIteration = false; } else { if(data[i].first != currentVertex.first) { if(data[i].first.x() != currentVertex.first.x()) { processVertex(output); //std::cout << scanline.size() << " "; countFromBelow.clear(); //should already be clear writeOutput(currentVertex.first.x(), result, output); currentVertex.second.clear(); mergeProperty(currentVertex.second, data[i].second); currentVertex.first = data[i].first; //std::cout << assertRedundant(scanline) << "/" << scanline.size() << " "; } else { processVertex(output); currentVertex.second.clear(); mergeProperty(currentVertex.second, data[i].second); currentVertex.first = data[i].first; } } else { mergeProperty(currentVertex.second, data[i].second); } } } processVertex(output); writeOutput(currentVertex.first.x(), result, output); //std::cout << assertRedundant(scanline) << "/" << scanline.size() << "\n"; //std::cout << scanline.size() << "\n"; } private: //private supporting types template <class T> class less_vertex_data { public: less_vertex_data() {} bool operator()(const T& lvalue, const T& rvalue) const { if(lvalue.first.x() < rvalue.first.x()) return true; if(lvalue.first.x() > rvalue.first.x()) return false; if(lvalue.first.y() < rvalue.first.y()) return true; return false; } }; template <typename T> struct lessPropertyCount { lessPropertyCount() {} bool operator()(const T& a, const T& b) { return a.first < b.first; } }; //private static member functions static inline void mergeProperty(property_map& lvalue, std::pair<property_type, int>& rvalue) { typename property_map::iterator itr = std::lower_bound(lvalue.begin(), lvalue.end(), rvalue, lessPropertyCount<std::pair<property_type, int> >()); if(itr == lvalue.end() || (*itr).first != rvalue.first) { lvalue.insert(itr, rvalue); } else { (*itr).second += rvalue.second; if((*itr).second == 0) lvalue.erase(itr); } // if(assertSorted(lvalue)) { // std::cout << "in mergeProperty\n"; // exit(0); // } } // static inline bool assertSorted(property_map& pset) { // bool result = false; // for(std::size_t i = 1; i < pset.size(); ++i) { // if(pset[i] < pset[i-1]) { // std::cout << "Out of Order Error "; // result = true; // } // if(pset[i].first == pset[i-1].first) { // std::cout << "Duplicate Property Error "; // result = true; // } // if(pset[0].second == 0 || pset[1].second == 0) { // std::cout << "Empty Property Error "; // result = true; // } // } // return result; // } static inline void setProperty(property_set& pset, property_map& pmap) { for(typename property_map::iterator itr = pmap.begin(); itr != pmap.end(); ++itr) { if((*itr).second > 0) { pset.insert(pset.end(), (*itr).first); } } } //private data members edge_property_vector output; scanline_type scanline; vertex_data currentVertex; property_map tmpVector; coordinate_type previousY; property_map countFromBelow; scanline_iterator scanlinePosition; //private member functions inline void mergeCount(property_map& lvalue, property_map& rvalue) { typename property_map::iterator litr = lvalue.begin(); typename property_map::iterator ritr = rvalue.begin(); tmpVector.clear(); while(litr != lvalue.end() && ritr != rvalue.end()) { if((*litr).first <= (*ritr).first) { if(!tmpVector.empty() && (*litr).first == tmpVector.back().first) { tmpVector.back().second += (*litr).second; } else { tmpVector.push_back(*litr); } ++litr; } else if((*ritr).first <= (*litr).first) { if(!tmpVector.empty() && (*ritr).first == tmpVector.back().first) { tmpVector.back().second += (*ritr).second; } else { tmpVector.push_back(*ritr); } ++ritr; } } while(litr != lvalue.end()) { if(!tmpVector.empty() && (*litr).first == tmpVector.back().first) { tmpVector.back().second += (*litr).second; } else { tmpVector.push_back(*litr); } ++litr; } while(ritr != rvalue.end()) { if(!tmpVector.empty() && (*ritr).first == tmpVector.back().first) { tmpVector.back().second += (*ritr).second; } else { tmpVector.push_back(*ritr); } ++ritr; } lvalue.clear(); for(std::size_t i = 0; i < tmpVector.size(); ++i) { if(tmpVector[i].second != 0) { lvalue.push_back(tmpVector[i]); } } // if(assertSorted(lvalue)) { // std::cout << "in mergeCount\n"; // exit(0); // } } inline void processVertex(edge_property_vector& output) { if(!countFromBelow.empty()) { //we are processing an interval of change in scanline state between //previous vertex position and current vertex position where //count from below represents the change on the interval //foreach scanline element from previous to current we //write the interval on the scanline that is changing //the old value and the new value to output property_merge_interval<coordinate_type> currentInterval(previousY, currentVertex.first.y()); coordinate_type currentY = currentInterval.low(); if(scanlinePosition == scanline.end() || (*scanlinePosition).first != previousY) { scanlinePosition = scanline.lower_bound(previousY); } scanline_iterator previousScanlinePosition = scanlinePosition; ++scanlinePosition; while(scanlinePosition != scanline.end()) { coordinate_type elementY = (*scanlinePosition).first; if(elementY <= currentInterval.high()) { property_map& countOnLeft = (*previousScanlinePosition).second; edge_property element; output.push_back(element); output.back().first = property_merge_interval<coordinate_type>((*previousScanlinePosition).first, elementY); setProperty(output.back().second.first, countOnLeft); mergeCount(countOnLeft, countFromBelow); setProperty(output.back().second.second, countOnLeft); if(output.back().second.first == output.back().second.second) { output.pop_back(); //it was an internal vertical edge, not to be output } else if(output.size() > 1) { edge_property& secondToLast = output[output.size()-2]; if(secondToLast.first.high() == output.back().first.low() && secondToLast.second.first == output.back().second.first && secondToLast.second.second == output.back().second.second) { //merge output onto previous output because properties are //identical on both sides implying an internal horizontal edge secondToLast.first.high(output.back().first.high()); output.pop_back(); } } if(previousScanlinePosition == scanline.begin()) { if(countOnLeft.empty()) { scanline.erase(previousScanlinePosition); } } else { scanline_iterator tmpitr = previousScanlinePosition; --tmpitr; if((*tmpitr).second == (*previousScanlinePosition).second) scanline.erase(previousScanlinePosition); } } else if(currentY < currentInterval.high()){ //elementY > currentInterval.high() //split the interval between previous and current scanline elements std::pair<coordinate_type, property_map> elementScan; elementScan.first = currentInterval.high(); elementScan.second = (*previousScanlinePosition).second; scanlinePosition = scanline.insert(scanlinePosition, elementScan); continue; } else { break; } previousScanlinePosition = scanlinePosition; currentY = previousY = elementY; ++scanlinePosition; if(scanlinePosition == scanline.end() && currentY < currentInterval.high()) { //insert a new element for top of range std::pair<coordinate_type, property_map> elementScan; elementScan.first = currentInterval.high(); scanlinePosition = scanline.insert(scanline.end(), elementScan); } } if(scanlinePosition == scanline.end() && currentY < currentInterval.high()) { //handle case where we iterated to end of the scanline //we need to insert an element into the scanline at currentY //with property value coming from below //and another one at currentInterval.high() with empty property value mergeCount(scanline[currentY], countFromBelow); std::pair<coordinate_type, property_map> elementScan; elementScan.first = currentInterval.high(); scanline.insert(scanline.end(), elementScan); edge_property element; output.push_back(element); output.back().first = property_merge_interval<coordinate_type>(currentY, currentInterval.high()); setProperty(output.back().second.second, countFromBelow); mergeCount(countFromBelow, currentVertex.second); } else { mergeCount(countFromBelow, currentVertex.second); if(countFromBelow.empty()) { if(previousScanlinePosition == scanline.begin()) { if((*previousScanlinePosition).second.empty()) { scanline.erase(previousScanlinePosition); //previousScanlinePosition = scanline.end(); //std::cout << "ERASE_A "; } } else { scanline_iterator tmpitr = previousScanlinePosition; --tmpitr; if((*tmpitr).second == (*previousScanlinePosition).second) { scanline.erase(previousScanlinePosition); //previousScanlinePosition = scanline.end(); //std::cout << "ERASE_B "; } } } } } else { //count from below is empty, we are starting a new interval of change countFromBelow = currentVertex.second; scanlinePosition = scanline.lower_bound(currentVertex.first.y()); if(scanlinePosition != scanline.end()) { if((*scanlinePosition).first != currentVertex.first.y()) { if(scanlinePosition != scanline.begin()) { //decrement to get the lower position of the first interval this vertex intersects --scanlinePosition; //insert a new element into the scanline for the incoming vertex property_map& countOnLeft = (*scanlinePosition).second; std::pair<coordinate_type, property_map> element(currentVertex.first.y(), countOnLeft); scanlinePosition = scanline.insert(scanlinePosition, element); } else { property_map countOnLeft; std::pair<coordinate_type, property_map> element(currentVertex.first.y(), countOnLeft); scanlinePosition = scanline.insert(scanlinePosition, element); } } } else { property_map countOnLeft; std::pair<coordinate_type, property_map> element(currentVertex.first.y(), countOnLeft); scanlinePosition = scanline.insert(scanlinePosition, element); } } previousY = currentVertex.first.y(); } template <typename T> inline int assertRedundant(T& t) { if(t.empty()) return 0; int count = 0; typename T::iterator itr = t.begin(); if((*itr).second.empty()) ++count; typename T::iterator itr2 = itr; ++itr2; while(itr2 != t.end()) { if((*itr).second == (*itr2).second) ++count; itr = itr2; ++itr2; } return count; } template <typename T> inline void performExtract(T& result, property_merge_data& data) { if(data.empty()) return; //sort polygon_sort(data.begin(), data.end(), less_vertex_data<vertex_property>()); //scanline bool firstIteration = true; scanlinePosition = scanline.end(); for(std::size_t i = 0; i < data.size(); ++i) { if(firstIteration) { mergeProperty(currentVertex.second, data[i].second); currentVertex.first = data[i].first; firstIteration = false; } else { if(data[i].first != currentVertex.first) { if(data[i].first.x() != currentVertex.first.x()) { processVertex(output); //std::cout << scanline.size() << " "; countFromBelow.clear(); //should already be clear writeGraph(result, output, scanline); currentVertex.second.clear(); mergeProperty(currentVertex.second, data[i].second); currentVertex.first = data[i].first; } else { processVertex(output); currentVertex.second.clear(); mergeProperty(currentVertex.second, data[i].second); currentVertex.first = data[i].first; } } else { mergeProperty(currentVertex.second, data[i].second); } } } processVertex(output); writeGraph(result, output, scanline); //std::cout << scanline.size() << "\n"; } template <typename T> inline void insertEdges(T& graph, property_set& p1, property_set& p2) { for(typename property_set::iterator itr = p1.begin(); itr != p1.end(); ++itr) { for(typename property_set::iterator itr2 = p2.begin(); itr2 != p2.end(); ++itr2) { if(*itr != *itr2) { graph[*itr].insert(*itr2); graph[*itr2].insert(*itr); } } } } template <typename T> inline void propertySetAbove(coordinate_type y, property_set& ps, T& scanline) { ps.clear(); typename T::iterator itr = scanline.find(y); if(itr != scanline.end()) setProperty(ps, (*itr).second); } template <typename T> inline void propertySetBelow(coordinate_type y, property_set& ps, T& scanline) { ps.clear(); typename T::iterator itr = scanline.find(y); if(itr != scanline.begin()) { --itr; setProperty(ps, (*itr).second); } } template <typename T, typename T2> inline void writeGraph(T& graph, edge_property_vector& output, T2& scanline) { if(output.empty()) return; edge_property* previousEdgeP = &(output[0]); bool firstIteration = true; property_set ps; for(std::size_t i = 0; i < output.size(); ++i) { edge_property& previousEdge = *previousEdgeP; edge_property& edge = output[i]; if(previousEdge.first.high() == edge.first.low()) { //horizontal edge insertEdges(graph, edge.second.first, previousEdge.second.first); //corner 1 insertEdges(graph, edge.second.first, previousEdge.second.second); //other horizontal edge insertEdges(graph, edge.second.second, previousEdge.second.second); //corner 2 insertEdges(graph, edge.second.second, previousEdge.second.first); } else { if(!firstIteration){ //look up regions above previous edge propertySetAbove(previousEdge.first.high(), ps, scanline); insertEdges(graph, ps, previousEdge.second.first); insertEdges(graph, ps, previousEdge.second.second); } //look up regions below current edge in the scanline propertySetBelow(edge.first.high(), ps, scanline); insertEdges(graph, ps, edge.second.first); insertEdges(graph, ps, edge.second.second); } firstIteration = false; //vertical edge insertEdges(graph, edge.second.second, edge.second.first); //shared region to left insertEdges(graph, edge.second.second, edge.second.second); //shared region to right insertEdges(graph, edge.second.first, edge.second.first); previousEdgeP = &(output[i]); } edge_property& previousEdge = *previousEdgeP; propertySetAbove(previousEdge.first.high(), ps, scanline); insertEdges(graph, ps, previousEdge.second.first); insertEdges(graph, ps, previousEdge.second.second); output.clear(); } template <typename Result> inline void writeOutput(coordinate_type x, Result& result, edge_property_vector& output) { for(std::size_t i = 0; i < output.size(); ++i) { edge_property& edge = output[i]; //edge.second.first is the property set on the left of the edge if(!edge.second.first.empty()) { typename Result::iterator itr = result.find(edge.second.first); if(itr == result.end()) { std::pair<property_set, polygon_set_type> element(edge.second.first, polygon_set_type(VERTICAL)); itr = result.insert(result.end(), element); } std::pair<interval_data<coordinate_type>, int> element2(interval_data<coordinate_type>(edge.first.low(), edge.first.high()), -1); //right edge of figure (*itr).second.insert(x, element2); } if(!edge.second.second.empty()) { //edge.second.second is the property set on the right of the edge typename Result::iterator itr = result.find(edge.second.second); if(itr == result.end()) { std::pair<property_set, polygon_set_type> element(edge.second.second, polygon_set_type(VERTICAL)); itr = result.insert(result.end(), element); } std::pair<interval_data<coordinate_type>, int> element3(interval_data<coordinate_type>(edge.first.low(), edge.first.high()), 1); //left edge of figure (*itr).second.insert(x, element3); } } output.clear(); } }; } } #endif detail/boolean_op_45.hpp 0000644 00000160422 15125572616 0011163 0 ustar 00 /* 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_BOOLEAN_OP_45_HPP #define BOOST_POLYGON_BOOLEAN_OP_45_HPP namespace boost { namespace polygon{ template <typename Unit> struct boolean_op_45 { typedef point_data<Unit> Point; typedef typename coordinate_traits<Unit>::manhattan_area_type LongUnit; class Count2 { public: inline Count2() #ifndef BOOST_POLYGON_MSVC : counts() #endif { counts[0] = counts[1] = 0; } //inline Count2(int count) { counts[0] = counts[1] = count; } inline Count2(int count1, int count2) #ifndef BOOST_POLYGON_MSVC : counts() #endif { counts[0] = count1; counts[1] = count2; } inline Count2(const Count2& count) #ifndef BOOST_POLYGON_MSVC : counts() #endif { counts[0] = count.counts[0]; counts[1] = count.counts[1]; } inline bool operator==(const Count2& count) const { return counts[0] == count.counts[0] && counts[1] == count.counts[1]; } inline bool operator!=(const Count2& count) const { return !((*this) == count); } inline Count2& operator=(int count) { counts[0] = counts[1] = count; return *this; } inline Count2& operator=(const Count2& count) { counts[0] = count.counts[0]; counts[1] = count.counts[1]; return *this; } inline int& operator[](bool index) { return counts[index]; } inline int operator[](bool index) const {return counts[index]; } inline Count2& operator+=(const Count2& count){ counts[0] += count[0]; counts[1] += count[1]; return *this; } inline Count2& operator-=(const Count2& count){ counts[0] -= count[0]; counts[1] -= count[1]; return *this; } inline Count2 operator+(const Count2& count) const { return Count2(*this)+=count; } inline Count2 operator-(const Count2& count) const { return Count2(*this)-=count; } inline Count2 invert() const { return Count2(-counts[0], -counts[1]); } private: int counts[2]; }; class Count1 { public: inline Count1() : count_(0) { } inline Count1(int count) : count_(count) { } inline Count1(const Count1& count) : count_(count.count_) { } inline bool operator==(const Count1& count) const { return count_ == count.count_; } inline bool operator!=(const Count1& count) const { return !((*this) == count); } inline Count1& operator=(int count) { count_ = count; return *this; } inline Count1& operator=(const Count1& count) { count_ = count.count_; return *this; } inline Count1& operator+=(const Count1& count){ count_ += count.count_; return *this; } inline Count1& operator-=(const Count1& count){ count_ -= count.count_; return *this; } inline Count1 operator+(const Count1& count) const { return Count1(*this)+=count; } inline Count1 operator-(const Count1& count) const { return Count1(*this)-=count; } inline Count1 invert() const { return Count1(-count_); } int count_; }; // inline std::ostream& operator<< (std::ostream& o, const Count2& c) { // o << c[0] << " " << c[1]; // return o; // } template <typename CountType> class Scan45ElementT { public: Unit x; Unit y; int rise; //-1, 0, +1 mutable CountType count; inline Scan45ElementT() : x(), y(), rise(), count() {} inline Scan45ElementT(Unit xIn, Unit yIn, int riseIn, CountType countIn = CountType()) : x(xIn), y(yIn), rise(riseIn), count(countIn) {} inline Scan45ElementT(const Scan45ElementT& that) : x(that.x), y(that.y), rise(that.rise), count(that.count) {} inline Scan45ElementT& operator=(const Scan45ElementT& that) { x = that.x; y = that.y; rise = that.rise; count = that.count; return *this; } inline Unit evalAtX(Unit xIn) const { return y + rise * (xIn - x); } inline bool cross(Point& crossPoint, const Scan45ElementT& edge, Unit currentX) const { Unit y1 = evalAtX(currentX); Unit y2 = edge.evalAtX(currentX); int rise1 = rise; int rise2 = edge.rise; if(rise > edge.rise){ if(y1 > y2) return false; } else if(rise < edge.rise){ if(y2 > y1) return false; std::swap(y1, y2); std::swap(rise1, rise2); } else { return false; } if(rise1 == 1) { if(rise2 == 0) { crossPoint = Point(currentX + y2 - y1, y2); } else { //rise2 == -1 Unit delta = (y2 - y1)/2; crossPoint = Point(currentX + delta, y1 + delta); } } else { //rise1 == 0 and rise2 == -1 crossPoint = Point(currentX + y2 - y1, y1); } return true; } }; typedef Scan45ElementT<Count2> Scan45Element; // inline std::ostream& operator<< (std::ostream& o, const Scan45Element& c) { // o << c.x << " " << c.y << " " << c.rise << " " << c.count; // return o; // } class lessScan45ElementRise { public: typedef Scan45Element first_argument_type; typedef Scan45Element second_argument_type; typedef bool result_type; inline lessScan45ElementRise() {} //default constructor is only constructor inline bool operator () (Scan45Element elm1, Scan45Element elm2) const { return elm1.rise < elm2.rise; } }; template <typename CountType> class lessScan45Element { private: Unit *x_; //x value at which to apply comparison int *justBefore_; public: inline lessScan45Element() : x_(0), justBefore_(0) {} inline lessScan45Element(Unit *x, int *justBefore) : x_(x), justBefore_(justBefore) {} inline lessScan45Element(const lessScan45Element& that) : x_(that.x_), justBefore_(that.justBefore_) {} inline lessScan45Element& operator=(const lessScan45Element& that) { x_ = that.x_; justBefore_ = that.justBefore_; return *this; } inline bool operator () (const Scan45ElementT<CountType>& elm1, const Scan45ElementT<CountType>& elm2) const { Unit y1 = elm1.evalAtX(*x_); Unit y2 = elm2.evalAtX(*x_); if(y1 < y2) return true; if(y1 == y2) { //if justBefore is true we invert the result of the comparison of slopes if(*justBefore_) { return elm1.rise > elm2.rise; } else { return elm1.rise < elm2.rise; } } return false; } }; template <typename CountType> class Scan45CountT { public: inline Scan45CountT() : counts() {} //counts[0] = counts[1] = counts[2] = counts[3] = 0; } inline Scan45CountT(CountType count) : counts() { counts[0] = counts[1] = counts[2] = counts[3] = count; } inline Scan45CountT(const CountType& count1, const CountType& count2, const CountType& count3, const CountType& count4) : counts() { counts[0] = count1; counts[1] = count2; counts[2] = count3; counts[3] = count4; } inline Scan45CountT(const Scan45CountT& count) : counts() { (*this) = count; } inline bool operator==(const Scan45CountT& count) const { for(unsigned int i = 0; i < 4; ++i) { if(counts[i] != count.counts[i]) return false; } return true; } inline bool operator!=(const Scan45CountT& count) const { return !((*this) == count); } inline Scan45CountT& operator=(CountType count) { counts[0] = counts[1] = counts[2] = counts[3] = count; return *this; } inline Scan45CountT& operator=(const Scan45CountT& count) { for(unsigned int i = 0; i < 4; ++i) { counts[i] = count.counts[i]; } return *this; } inline CountType& operator[](int index) { return counts[index]; } inline CountType operator[](int index) const {return counts[index]; } inline Scan45CountT& operator+=(const Scan45CountT& count){ for(unsigned int i = 0; i < 4; ++i) { counts[i] += count.counts[i]; } return *this; } inline Scan45CountT& operator-=(const Scan45CountT& count){ for(unsigned int i = 0; i < 4; ++i) { counts[i] -= count.counts[i]; } return *this; } inline Scan45CountT operator+(const Scan45CountT& count) const { return Scan45CountT(*this)+=count; } inline Scan45CountT operator-(const Scan45CountT& count) const { return Scan45CountT(*this)-=count; } inline Scan45CountT invert() const { return Scan45CountT(CountType())-=(*this); } inline Scan45CountT& operator+=(const Scan45ElementT<CountType>& element){ counts[element.rise+1] += element.count; return *this; } private: CountType counts[4]; }; typedef Scan45CountT<Count2> Scan45Count; // inline std::ostream& operator<< (std::ostream& o, const Scan45Count& c) { // o << c[0] << ", " << c[1] << ", "; // o << c[2] << ", " << c[3]; // return o; // } // inline std::ostream& operator<< (std::ostream& o, const Scan45Vertex& c) { // o << c.first << ": " << c.second; // return o; // } //vetex45 is sortable template <typename ct> class Vertex45T { public: Point pt; int rise; // 1, 0 or -1 ct count; //dxdydTheta inline Vertex45T() : pt(), rise(), count() {} inline Vertex45T(const Point& point, int riseIn, ct countIn) : pt(point), rise(riseIn), count(countIn) {} inline Vertex45T(const Vertex45T& vertex) : pt(vertex.pt), rise(vertex.rise), count(vertex.count) {} inline Vertex45T& operator=(const Vertex45T& vertex){ pt = vertex.pt; rise = vertex.rise; count = vertex.count; return *this; } inline bool operator==(const Vertex45T& vertex) const { return pt == vertex.pt && rise == vertex.rise && count == vertex.count; } inline bool operator!=(const Vertex45T& vertex) const { return !((*this) == vertex); } inline bool operator<(const Vertex45T& vertex) const { if(pt.x() < vertex.pt.x()) return true; if(pt.x() == vertex.pt.x()) { if(pt.y() < vertex.pt.y()) return true; if(pt.y() == vertex.pt.y()) { return rise < vertex.rise; } } return false; } inline bool operator>(const Vertex45T& vertex) const { return vertex < (*this); } inline bool operator<=(const Vertex45T& vertex) const { return !((*this) > vertex); } inline bool operator>=(const Vertex45T& vertex) const { return !((*this) < vertex); } inline Unit evalAtX(Unit xIn) const { return pt.y() + rise * (xIn - pt.x()); } }; typedef Vertex45T<int> Vertex45; // inline std::ostream& operator<< (std::ostream& o, const Vertex45& c) { // o << c.pt << " " << c.rise << " " << c.count; // return o; // } //when scanning Vertex45 for polygon formation we need a scanline comparator functor class lessVertex45 { private: Unit *x_; //x value at which to apply comparison int *justBefore_; public: inline lessVertex45() : x_(0), justBefore_() {} inline lessVertex45(Unit *x, int *justBefore) : x_(x), justBefore_(justBefore) {} inline lessVertex45(const lessVertex45& that) : x_(that.x_), justBefore_(that.justBefore_) {} inline lessVertex45& operator=(const lessVertex45& that) { x_ = that.x_; justBefore_ = that.justBefore_; return *this; } template <typename ct> inline bool operator () (const Vertex45T<ct>& elm1, const Vertex45T<ct>& elm2) const { Unit y1 = elm1.evalAtX(*x_); Unit y2 = elm2.evalAtX(*x_); if(y1 < y2) return true; if(y1 == y2) { //if justBefore is true we invert the result of the comparison of slopes if(*justBefore_) { return elm1.rise > elm2.rise; } else { return elm1.rise < elm2.rise; } } return false; } }; // 0 right to left // 1 upper right to lower left // 2 high to low // 3 upper left to lower right // 4 left to right // 5 lower left to upper right // 6 low to high // 7 lower right to upper left static inline int classifyEdge45(const Point& prevPt, const Point& nextPt) { if(prevPt.x() == nextPt.x()) { //2 or 6 return predicated_value(prevPt.y() < nextPt.y(), 6, 2); } if(prevPt.y() == nextPt.y()) { //0 or 4 return predicated_value(prevPt.x() < nextPt.x(), 4, 0); } if(prevPt.x() < nextPt.x()) { //3 or 5 return predicated_value(prevPt.y() < nextPt.y(), 5, 3); } //prevPt.x() > nextPt.y() //1 or 7 return predicated_value(prevPt.y() < nextPt.y(), 7, 1); } template <int op, typename CountType> static int applyLogic(CountType count1, CountType count2){ bool l1 = applyLogic<op>(count1); bool l2 = applyLogic<op>(count2); if(l1 && !l2) return -1; //was true before and became false like a trailing edge if(!l1 && l2) return 1; //was false before and became true like a leading edge return 0; //no change in logic between the two counts } template <int op> static bool applyLogic(Count2 count) { #ifdef BOOST_POLYGON_MSVC #pragma warning (push) #pragma warning (disable: 4127) #endif if(op == 0) { //apply or return count[0] > 0 || count[1] > 0; } else if(op == 1) { //apply and return count[0] > 0 && count[1] > 0; } else if(op == 2) { //apply not return count[0] > 0 && !(count[1] > 0); } else if(op == 3) { //apply xor return (count[0] > 0) ^ (count[1] > 0); } else return false; #ifdef BOOST_POLYGON_MSVC #pragma warning (pop) #endif } template <int op> struct boolean_op_45_output_functor { template <typename cT> void operator()(cT& output, const Count2& count1, const Count2& count2, const Point& pt, int rise, direction_1d end) { int edgeType = applyLogic<op>(count1, count2); if(edgeType) { int multiplier = end == LOW ? -1 : 1; //std::cout << "cross logic: " << edgeType << "\n"; output.insert(output.end(), Vertex45(pt, rise, edgeType * multiplier)); //std::cout << "write out: " << crossPoint << " " << Point(eraseItrs[i]->x, eraseItrs[i]->y) << "\n"; } } }; template <int op> static bool applyLogic(Count1 count) { #ifdef BOOST_POLYGON_MSVC #pragma warning (push) #pragma warning (disable: 4127) #endif if(op == 0) { //apply or return count.count_ > 0; } else if(op == 1) { //apply and return count.count_ > 1; } else if(op == 3) { //apply xor return (count.count_ % 2) != 0; } else return false; #ifdef BOOST_POLYGON_MSVC #pragma warning (pop) #endif } template <int op> struct unary_op_45_output_functor { template <typename cT> void operator()(cT& output, const Count1& count1, const Count1& count2, const Point& pt, int rise, direction_1d end) { int edgeType = applyLogic<op>(count1, count2); if(edgeType) { int multiplier = end == LOW ? -1 : 1; //std::cout << "cross logic: " << edgeType << "\n"; output.insert(output.end(), Vertex45(pt, rise, edgeType * multiplier)); //std::cout << "write out: " << crossPoint << " " << Point(eraseItrs[i]->x, eraseItrs[i]->y) << "\n"; } } }; class lessScan45Vertex { public: inline lessScan45Vertex() {} //default constructor is only constructor template <typename Scan45Vertex> inline bool operator () (const Scan45Vertex& v1, const Scan45Vertex& v2) const { return (v1.first.x() < v2.first.x()) || (v1.first.x() == v2.first.x() && v1.first.y() < v2.first.y()); } }; template <typename S45V> static inline void sortScan45Vector(S45V& vec) { polygon_sort(vec.begin(), vec.end(), lessScan45Vertex()); } template <typename CountType, typename output_functor> class Scan45 { public: typedef Scan45CountT<CountType> Scan45Count; typedef std::pair<Point, Scan45Count> Scan45Vertex; //index is the index into the vertex static inline Scan45Element getElement(const Scan45Vertex& vertex, int index) { return Scan45Element(vertex.first.x(), vertex.first.y(), index - 1, vertex.second[index]); } class lessScan45Point { public: typedef Point first_argument_type; typedef Point second_argument_type; typedef bool result_type; inline lessScan45Point() {} //default constructor is only constructor inline bool operator () (const Point& v1, const Point& v2) const { return (v1.x() < v2.x()) || (v1.x() == v2.x() && v1.y() < v2.y()); } }; typedef std::vector<Scan45Vertex> Scan45Vector; //definitions typedef std::set<Scan45ElementT<CountType>, lessScan45Element<CountType> > Scan45Data; typedef typename Scan45Data::iterator iterator; typedef typename Scan45Data::const_iterator const_iterator; typedef std::set<Point, lessScan45Point> CrossQueue; //data Scan45Data scanData_; CrossQueue crossQueue_; Scan45Vector crossVector_; Unit x_; int justBefore_; public: inline Scan45() : scanData_(), crossQueue_(), crossVector_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false) { lessScan45Element<CountType> lessElm(&x_, &justBefore_); scanData_ = std::set<Scan45ElementT<CountType>, lessScan45Element<CountType> >(lessElm); } inline Scan45(const Scan45& that) : scanData_(), crossQueue_(), crossVector_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false) { (*this) = that; } inline Scan45& operator=(const Scan45& that) { x_ = that.x_; justBefore_ = that.justBefore_; crossQueue_ = that.crossQueue_; crossVector_ = that.crossVector_; lessScan45Element<CountType> lessElm(&x_, &justBefore_); scanData_ = std::set<Scan45ElementT<CountType>, lessScan45Element<CountType> >(lessElm); for(const_iterator itr = that.scanData_.begin(); itr != that.scanData_.end(); ++itr){ scanData_.insert(scanData_.end(), *itr); } return *this; } //cT is an output container of Vertex45 //iT is an iterator over Scan45Vertex elements template <class cT, class iT> void scan(cT& output, iT inputBegin, iT inputEnd) { //std::cout << "1\n"; while(inputBegin != inputEnd) { //std::cout << "2\n"; //std::cout << "x_ = " << x_ << "\n"; //std::cout << "scan line size: " << scanData_.size() << "\n"; //for(iterator iter = scanData_.begin(); // iter != scanData_.end(); ++iter) { // std::cout << "scan element\n"; // std::cout << *iter << " " << iter->evalAtX(x_) << "\n"; // } // std::cout << "cross queue size: " << crossQueue_.size() << "\n"; // std::cout << "cross vector size: " << crossVector_.size() << "\n"; //for(CrossQueue::iterator cqitr = crossQueue_.begin(); cqitr != crossQueue_.end(); ++cqitr) { // std::cout << *cqitr << " "; //} std::cout << "\n"; Unit nextX = (*inputBegin).first.x(); if(!crossVector_.empty() && crossVector_[0].first.x() < nextX) nextX = crossVector_[0].first.x(); if(nextX != x_) { //std::cout << "3\n"; //we need to move to the next scanline stop //we need to process end events then cross events //process end events if(!crossQueue_.empty() && (*crossQueue_.begin()).x() < nextX) { //std::cout << "4\n"; nextX = (std::min)(nextX, (*crossQueue_.begin()).x()); } //std::cout << "6\n"; justBefore_ = true; x_ = nextX; advance_(output); justBefore_ = false; if(!crossVector_.empty() && nextX == (*inputBegin).first.x()) { inputBegin = mergeCross_(inputBegin, inputEnd); } processEvent_(output, crossVector_.begin(), crossVector_.end()); crossVector_.clear(); } else { //std::cout << "7\n"; //our scanline has progressed to the event that is next in the queue inputBegin = processEvent_(output, inputBegin, inputEnd); } } //std::cout << "done scanning\n"; } private: //functions template <class cT> inline void advance_(cT& output) { //process all cross points on the cross queue at the current x_ //std::cout << "advance_\n"; std::vector<iterator> eraseVec; while(!crossQueue_.empty() && (*crossQueue_.begin()).x() == x_){ //std::cout << "loop\n"; //pop point off the cross queue Point crossPoint = *(crossQueue_.begin()); //std::cout << crossPoint << "\n"; //for(iterator iter = scanData_.begin(); // iter != scanData_.end(); ++iter) { // std::cout << "scan element\n"; // std::cout << *iter << " " << iter->evalAtX(x_) << "\n"; //} crossQueue_.erase(crossQueue_.begin()); Scan45Vertex vertex(crossPoint, Scan45Count()); iterator lowIter = lookUp_(vertex.first.y()); //std::cout << "searching at: " << vertex.first.y() << "\n"; //if(lowIter == scanData_.end()) std::cout << "could not find\n"; //else std::cout << "found: " << *lowIter << "\n"; if(lowIter == scanData_.end() || lowIter->evalAtX(x_) != vertex.first.y()) { // std::cout << "skipping\n"; //there weren't any edges at this potential cross point continue; } CountType countBelow; iterator searchDownItr = lowIter; while(searchDownItr != scanData_.begin() && searchDownItr->evalAtX(x_) == vertex.first.y()) { //get count from below --searchDownItr; countBelow = searchDownItr->count; } //std::cout << "Below Count: " << countBelow << "\n"; Scan45Count count(countBelow); std::size_t numEdges = 0; iterator eraseItrs[3]; while(lowIter != scanData_.end() && lowIter->evalAtX(x_) == vertex.first.y()) { for(int index = lowIter->rise +1; index >= 0; --index) count[index] = lowIter->count; //std::cout << count << "\n"; eraseItrs[numEdges] = lowIter; ++numEdges; ++lowIter; } if(numEdges == 1) { //look for the next crossing point and continue //std::cout << "found only one edge\n"; findCross_(eraseItrs[0]); continue; } //before we erase the elements we need to decide if they should be written out CountType currentCount = countBelow; for(std::size_t i = 0; i < numEdges; ++i) { output_functor f; f(output, currentCount, eraseItrs[i]->count, crossPoint, eraseItrs[i]->rise, LOW); currentCount = eraseItrs[i]->count; } //schedule erase of the elements for(std::size_t i = 0; i < numEdges; ++i) { eraseVec.push_back(eraseItrs[i]); } //take the derivative wrt theta of the count at the crossing point vertex.second[2] = count[2] - countBelow; vertex.second[1] = count[1] - count[2]; vertex.second[0] = count[0] - count[1]; //add the point, deriviative pair into the cross vector //std::cout << "LOOK HERE!\n"; //std::cout << count << "\n"; //std::cout << vertex << "\n"; crossVector_.push_back(vertex); } //erase crossing elements std::vector<iterator> searchVec; for(std::size_t i = 0; i < eraseVec.size(); ++i) { if(eraseVec[i] != scanData_.begin()) { iterator searchItr = eraseVec[i]; --searchItr; if(searchVec.empty() || searchVec.back() != searchItr) searchVec.push_back(searchItr); } scanData_.erase(eraseVec[i]); } for(std::size_t i = 0; i < searchVec.size(); ++i) { findCross_(searchVec[i]); } } template <class iT> inline iT mergeCross_(iT inputBegin, iT inputEnd) { Scan45Vector vec; swap(vec, crossVector_); iT mergeEnd = inputBegin; std::size_t mergeCount = 0; while(mergeEnd != inputEnd && (*mergeEnd).first.x() == x_) { ++mergeCount; ++mergeEnd; } crossVector_.reserve((std::max)(vec.capacity(), vec.size() + mergeCount)); for(std::size_t i = 0; i < vec.size(); ++i){ while(inputBegin != mergeEnd && (*inputBegin).first.y() < vec[i].first.y()) { crossVector_.push_back(*inputBegin); ++inputBegin; } crossVector_.push_back(vec[i]); } while(inputBegin != mergeEnd){ crossVector_.push_back(*inputBegin); ++inputBegin; } return inputBegin; } template <class cT, class iT> inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { //std::cout << "processEvent_\n"; CountType verticalCount = CountType(); Point prevPoint; iterator prevIter = scanData_.end(); while(inputBegin != inputEnd && (*inputBegin).first.x() == x_) { //std::cout << (*inputBegin) << "\n"; //std::cout << "loop\n"; Scan45Vertex vertex = *inputBegin; //std::cout << vertex.first << "\n"; //if vertical count propigating up fake a null event at the next element if(verticalCount != CountType() && (prevIter != scanData_.end() && prevIter->evalAtX(x_) < vertex.first.y())) { //std::cout << "faking null event\n"; vertex = Scan45Vertex(Point(x_, prevIter->evalAtX(x_)), Scan45Count()); } else { ++inputBegin; //std::cout << "after increment\n"; //accumulate overlapping changes in Scan45Count while(inputBegin != inputEnd && (*inputBegin).first.x() == x_ && (*inputBegin).first.y() == vertex.first.y()) { //std::cout << "accumulate\n"; vertex.second += (*inputBegin).second; ++inputBegin; } } //std::cout << vertex.second << "\n"; //integrate vertex CountType currentCount = verticalCount;// + vertex.second[0]; for(unsigned int i = 0; i < 3; ++i) { vertex.second[i] = currentCount += vertex.second[i]; } //std::cout << vertex.second << "\n"; //vertex represents the change in state at this point //get counts at current vertex CountType countBelow; iterator lowIter = lookUp_(vertex.first.y()); if(lowIter != scanData_.begin()) { //get count from below --lowIter; countBelow = lowIter->count; ++lowIter; } //std::cout << "Count Below: " << countBelow[0] << " " << countBelow[1] << "\n"; //std::cout << "vertical count: " << verticalCount[0] << " " << verticalCount[1] << "\n"; Scan45Count countAt(countBelow - verticalCount); //check if the vertical edge should be written out if(verticalCount != CountType()) { output_functor f; f(output, countBelow - verticalCount, countBelow, prevPoint, 2, HIGH); f(output, countBelow - verticalCount, countBelow, vertex.first, 2, LOW); } currentCount = countBelow - verticalCount; while(lowIter != scanData_.end() && lowIter->evalAtX(x_) == vertex.first.y()) { for(unsigned int i = lowIter->rise + 1; i < 3; ++i) { countAt[i] = lowIter->count; } Point lp(lowIter->x, lowIter->y); if(lp != vertex.first) { output_functor f; f(output, currentCount, lowIter->count, vertex.first, lowIter->rise, LOW); } currentCount = lowIter->count; iterator nextIter = lowIter; ++nextIter; //std::cout << "erase\n"; scanData_.erase(lowIter); if(nextIter != scanData_.end()) findCross_(nextIter); lowIter = nextIter; } verticalCount += vertex.second[3]; prevPoint = vertex.first; //std::cout << "new vertical count: " << verticalCount[0] << " " << verticalCount[1] << "\n"; prevIter = lowIter; //count represents the current state at this point //std::cout << vertex.second << "\n"; //std::cout << countAt << "\n"; //std::cout << "ADD\n"; vertex.second += countAt; //std::cout << vertex.second << "\n"; //add elements to the scanline for(int i = 0; i < 3; ++i) { if(vertex.second[i] != countBelow) { //std::cout << "insert: " << vertex.first.x() << " " << vertex.first.y() << " " << i-1 << // " " << vertex.second[i][0] << " " << vertex.second[i][1] << "\n"; iterator insertIter = scanData_.insert(scanData_.end(), Scan45ElementT<CountType>(vertex.first.x(), vertex.first.y(), i - 1, vertex.second[i])); findCross_(insertIter); output_functor f; f(output, countBelow, vertex.second[i], vertex.first, i - 1, HIGH); } countBelow = vertex.second[i]; } } //std::cout << "end processEvent\n"; return inputBegin; } //iter1 is horizontal inline void scheduleCross0_(iterator iter1, iterator iter2) { //std::cout << "0, "; Unit y1 = iter1->evalAtX(x_); Unit y2 = iter2->evalAtX(x_); LongUnit delta = local_abs(LongUnit(y1) - LongUnit(y2)); if(delta + static_cast<LongUnit>(x_) <= (std::numeric_limits<Unit>::max)()) crossQueue_.insert(crossQueue_.end(), Point(x_ + static_cast<Unit>(delta), y1)); //std::cout << Point(x_ + delta, y1); } //neither iter is horizontal inline void scheduleCross1_(iterator iter1, iterator iter2) { //std::cout << "1, "; Unit y1 = iter1->evalAtX(x_); Unit y2 = iter2->evalAtX(x_); //std::cout << y1 << " " << y2 << ": "; //note that half the delta cannot exceed the positive inter range LongUnit delta = y1; delta -= y2; Unit UnitMax = (std::numeric_limits<Unit>::max)(); if((delta & 1) == 1) { //delta is odd, division by 2 will result in integer trunctaion if(delta == 1) { //the cross point is not on the integer grid and cannot be represented //we must throw an exception std::string msg = "GTL 45 Boolean error, precision insufficient to represent edge intersection coordinate value."; throw(msg); } else { //note that result of this subtraction is always positive because itr1 is above itr2 in scanline LongUnit halfDelta2 = (LongUnit)((((LongUnit)y1) - y2)/2); //note that halfDelta2 has been truncated if(halfDelta2 + x_ <= UnitMax && halfDelta2 + y2 <= UnitMax) { crossQueue_.insert(crossQueue_.end(), Point(x_+static_cast<Unit>(halfDelta2), y2+static_cast<Unit>(halfDelta2))); crossQueue_.insert(crossQueue_.end(), Point(x_+static_cast<Unit>(halfDelta2), y2+static_cast<Unit>(halfDelta2)+1)); } } } else { LongUnit halfDelta = (LongUnit)((((LongUnit)y1) - y2)/2); if(halfDelta + x_ <= UnitMax && halfDelta + y2 <= UnitMax) crossQueue_.insert(crossQueue_.end(), Point(x_+static_cast<Unit>(halfDelta), y2+static_cast<Unit>(halfDelta))); //std::cout << Point(x_+halfDelta, y2+halfDelta); } } inline void findCross_(iterator iter) { //std::cout << "find cross "; iterator iteratorBelow = iter; iterator iteratorAbove = iter; if(iter != scanData_.begin() && iter->rise < 1) { --iteratorBelow; if(iter->rise == 0){ if(iteratorBelow->rise == 1) { scheduleCross0_(iter, iteratorBelow); } } else { //iter->rise == -1 if(iteratorBelow->rise == 1) { scheduleCross1_(iter, iteratorBelow); } else if(iteratorBelow->rise == 0) { scheduleCross0_(iteratorBelow, iter); } } } ++iteratorAbove; if(iteratorAbove != scanData_.end() && iter->rise > -1) { if(iter->rise == 0) { if(iteratorAbove->rise == -1) { scheduleCross0_(iter, iteratorAbove); } } else { //iter->rise == 1 if(iteratorAbove->rise == -1) { scheduleCross1_(iteratorAbove, iter); } else if(iteratorAbove->rise == 0) { scheduleCross0_(iteratorAbove, iter); } } } //std::cout << "\n"; } inline iterator lookUp_(Unit y){ //if just before then we need to look from 1 not -1 return scanData_.lower_bound(Scan45ElementT<CountType>(x_, y, -1+2*justBefore_)); } }; //template <typename CountType> //static inline void print45Data(const std::set<Scan45ElementT<CountType>, // lessScan45Element<CountType> >& data) { // typename std::set<Scan45ElementT<CountType>, lessScan45Element<CountType> >::const_iterator iter; // for(iter = data.begin(); iter != data.end(); ++iter) { // std::cout << iter->x << " " << iter->y << " " << iter->rise << "\n"; // } //} template <typename streamtype> static inline bool testScan45Data(streamtype& stdcout) { Unit x = 0; int justBefore = false; lessScan45Element<Count2> lessElm(&x, &justBefore); std::set<Scan45ElementT<Count2>, lessScan45Element<Count2> > testData(lessElm); //Unit size = testData.size(); typedef std::set<Scan45ElementT<Count2>, lessScan45Element<Count2> > Scan45Data; typename Scan45Data::iterator itr10 = testData.insert(testData.end(), Scan45Element(0, 10, 1)); typename Scan45Data::iterator itr20 = testData.insert(testData.end(), Scan45Element(0, 20, 1)); typename Scan45Data::iterator itr30 = testData.insert(testData.end(), Scan45Element(0, 30, -1)); typename Scan45Data::iterator itr40 = testData.insert(testData.end(), Scan45Element(0, 40, -1)); typename Scan45Data::iterator itrA = testData.lower_bound(Scan45Element(0, 29, -1)); typename Scan45Data::iterator itr1 = testData.lower_bound(Scan45Element(0, 10, -1)); x = 4; //now at 14 24 26 36 typename Scan45Data::iterator itrB = testData.lower_bound(Scan45Element(4, 29, -1)); typename Scan45Data::iterator itr2 = testData.lower_bound(Scan45Element(4, 14, -1)); if(itr1 != itr2) stdcout << "test1 failed\n"; if(itrA == itrB) stdcout << "test2 failed\n"; //remove crossing elements testData.erase(itr20); testData.erase(itr30); x = 5; itr20 = testData.insert(testData.end(), Scan45Element(0, 20, 1)); itr30 = testData.insert(testData.end(), Scan45Element(0, 30, -1)); //now at 15 25 25 35 typename Scan45Data::iterator itr = testData.begin(); if(itr != itr10) stdcout << "test3 failed\n"; ++itr; if(itr != itr30) stdcout << "test4 failed\n"; ++itr; if(itr != itr20) stdcout << "test5 failed\n"; ++itr; if(itr != itr40) stdcout << "test6 failed\n"; stdcout << "done testing Scan45Data\n"; return true; } template <typename stream_type> static inline bool testScan45Rect(stream_type& stdcout) { stdcout << "testing Scan45Rect\n"; Scan45<Count2, boolean_op_45_output_functor<0> > scan45; std::vector<Vertex45 > result; typedef std::pair<Point, Scan45Count> Scan45Vertex; std::vector<Scan45Vertex> vertices; //is a Rectnagle(0, 0, 10, 10); Count2 count(1, 0); Count2 ncount(-1, 0); vertices.push_back(Scan45Vertex(Point(0,0), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); vertices.push_back(Scan45Vertex(Point(0,10), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); vertices.push_back(Scan45Vertex(Point(10,0), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); vertices.push_back(Scan45Vertex(Point(10,10), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); stdcout << "scanning\n"; scan45.scan(result, vertices.begin(), vertices.end()); stdcout << "done scanning\n"; // result size == 8 // result == 0 0 0 1 // result == 0 0 2 1 // result == 0 10 2 -1 // result == 0 10 0 -1 // result == 10 0 0 -1 // result == 10 0 2 -1 // result == 10 10 2 1 // result == 10 10 0 1 std::vector<Vertex45> reference; reference.push_back(Vertex45(Point(0, 0), 0, 1)); reference.push_back(Vertex45(Point(0, 0), 2, 1)); reference.push_back(Vertex45(Point(0, 10), 2, -1)); reference.push_back(Vertex45(Point(0, 10), 0, -1)); reference.push_back(Vertex45(Point(10, 0), 0, -1)); reference.push_back(Vertex45(Point(10, 0), 2, -1)); reference.push_back(Vertex45(Point(10, 10), 2, 1)); reference.push_back(Vertex45(Point(10, 10), 0, 1)); if(result != reference) { stdcout << "result size == " << result.size() << "\n"; for(std::size_t i = 0; i < result.size(); ++i) { //std::cout << "result == " << result[i]<< "\n"; } stdcout << "reference size == " << reference.size() << "\n"; for(std::size_t i = 0; i < reference.size(); ++i) { //std::cout << "reference == " << reference[i]<< "\n"; } return false; } stdcout << "done testing Scan45Rect\n"; return true; } template <typename stream_type> static inline bool testScan45P1(stream_type& stdcout) { stdcout << "testing Scan45P1\n"; Scan45<Count2, boolean_op_45_output_functor<0> > scan45; std::vector<Vertex45 > result; typedef std::pair<Point, Scan45Count> Scan45Vertex; std::vector<Scan45Vertex> vertices; //is a Rectnagle(0, 0, 10, 10); Count2 count(1, 0); Count2 ncount(-1, 0); vertices.push_back(Scan45Vertex(Point(0,0), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); vertices.push_back(Scan45Vertex(Point(0,10), Scan45Count(Count2(0, 0), Count2(0, 0), ncount, ncount))); vertices.push_back(Scan45Vertex(Point(10,10), Scan45Count(Count2(0, 0), Count2(0, 0), ncount, ncount))); vertices.push_back(Scan45Vertex(Point(10,20), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); stdcout << "scanning\n"; scan45.scan(result, vertices.begin(), vertices.end()); stdcout << "done scanning\n"; // result size == 8 // result == 0 0 1 1 // result == 0 0 2 1 // result == 0 10 2 -1 // result == 0 10 1 -1 // result == 10 10 1 -1 // result == 10 10 2 -1 // result == 10 20 2 1 // result == 10 20 1 1 std::vector<Vertex45> reference; reference.push_back(Vertex45(Point(0, 0), 1, 1)); reference.push_back(Vertex45(Point(0, 0), 2, 1)); reference.push_back(Vertex45(Point(0, 10), 2, -1)); reference.push_back(Vertex45(Point(0, 10), 1, -1)); reference.push_back(Vertex45(Point(10, 10), 1, -1)); reference.push_back(Vertex45(Point(10, 10), 2, -1)); reference.push_back(Vertex45(Point(10, 20), 2, 1)); reference.push_back(Vertex45(Point(10, 20), 1, 1)); if(result != reference) { stdcout << "result size == " << result.size() << "\n"; for(std::size_t i = 0; i < result.size(); ++i) { //std::cout << "result == " << result[i]<< "\n"; } stdcout << "reference size == " << reference.size() << "\n"; for(std::size_t i = 0; i < reference.size(); ++i) { //std::cout << "reference == " << reference[i]<< "\n"; } return false; } stdcout << "done testing Scan45P1\n"; return true; } template <typename stream_type> static inline bool testScan45P2(stream_type& stdcout) { stdcout << "testing Scan45P2\n"; Scan45<Count2, boolean_op_45_output_functor<0> > scan45; std::vector<Vertex45 > result; typedef std::pair<Point, Scan45Count> Scan45Vertex; std::vector<Scan45Vertex> vertices; //is a Rectnagle(0, 0, 10, 10); Count2 count(1, 0); Count2 ncount(-1, 0); vertices.push_back(Scan45Vertex(Point(0,0), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(10,0), Scan45Count(Count2(0, 0), ncount, count, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(10,10), Scan45Count(Count2(0, 0), ncount, count, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(20,10), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); stdcout << "scanning\n"; scan45.scan(result, vertices.begin(), vertices.end()); stdcout << "done scanning\n"; // result size == 8 // result == 0 0 0 1 // result == 0 0 1 -1 // result == 10 0 0 -1 // result == 10 0 1 1 // result == 10 10 1 1 // result == 10 10 0 -1 // result == 20 10 1 -1 // result == 20 10 0 1 std::vector<Vertex45> reference; reference.push_back(Vertex45(Point(0, 0), 0, 1)); reference.push_back(Vertex45(Point(0, 0), 1, -1)); reference.push_back(Vertex45(Point(10, 0), 0, -1)); reference.push_back(Vertex45(Point(10, 0), 1, 1)); reference.push_back(Vertex45(Point(10, 10), 1, 1)); reference.push_back(Vertex45(Point(10, 10), 0, -1)); reference.push_back(Vertex45(Point(20, 10), 1, -1)); reference.push_back(Vertex45(Point(20, 10), 0, 1)); if(result != reference) { stdcout << "result size == " << result.size() << "\n"; for(std::size_t i = 0; i < result.size(); ++i) { //stdcout << "result == " << result[i]<< "\n"; } stdcout << "reference size == " << reference.size() << "\n"; for(std::size_t i = 0; i < reference.size(); ++i) { //stdcout << "reference == " << reference[i]<< "\n"; } return false; } stdcout << "done testing Scan45P2\n"; return true; } template <typename streamtype> static inline bool testScan45And(streamtype& stdcout) { stdcout << "testing Scan45And\n"; Scan45<Count2, boolean_op_45_output_functor<1> > scan45; std::vector<Vertex45 > result; typedef std::pair<Point, Scan45Count> Scan45Vertex; std::vector<Scan45Vertex> vertices; //is a Rectnagle(0, 0, 10, 10); Count2 count(1, 0); Count2 ncount(-1, 0); vertices.push_back(Scan45Vertex(Point(0,0), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); vertices.push_back(Scan45Vertex(Point(0,10), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); vertices.push_back(Scan45Vertex(Point(10,0), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); vertices.push_back(Scan45Vertex(Point(10,10), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); count = Count2(0, 1); ncount = count.invert(); vertices.push_back(Scan45Vertex(Point(2,2), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); vertices.push_back(Scan45Vertex(Point(2,12), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); vertices.push_back(Scan45Vertex(Point(12,2), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); vertices.push_back(Scan45Vertex(Point(12,12), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); sortScan45Vector(vertices); stdcout << "scanning\n"; scan45.scan(result, vertices.begin(), vertices.end()); stdcout << "done scanning\n"; //result size == 8 //result == 2 2 0 1 //result == 2 2 2 1 //result == 2 10 2 -1 //result == 2 10 0 -1 //result == 10 2 0 -1 //result == 10 2 2 -1 //result == 10 10 2 1 //result == 10 10 0 1 std::vector<Vertex45> reference; reference.push_back(Vertex45(Point(2, 2), 0, 1)); reference.push_back(Vertex45(Point(2, 2), 2, 1)); reference.push_back(Vertex45(Point(2, 10), 2, -1)); reference.push_back(Vertex45(Point(2, 10), 0, -1)); reference.push_back(Vertex45(Point(10, 2), 0, -1)); reference.push_back(Vertex45(Point(10, 2), 2, -1)); reference.push_back(Vertex45(Point(10, 10), 2, 1)); reference.push_back(Vertex45(Point(10, 10), 0, 1)); if(result != reference) { stdcout << "result size == " << result.size() << "\n"; for(std::size_t i = 0; i < result.size(); ++i) { //stdcout << "result == " << result[i]<< "\n"; } stdcout << "reference size == " << reference.size() << "\n"; for(std::size_t i = 0; i < reference.size(); ++i) { //stdcout << "reference == " << reference[i]<< "\n"; } return false; } stdcout << "done testing Scan45And\n"; return true; } template <typename stream_type> static inline bool testScan45Star1(stream_type& stdcout) { stdcout << "testing Scan45Star1\n"; Scan45<Count2, boolean_op_45_output_functor<0> > scan45; std::vector<Vertex45 > result; typedef std::pair<Point, Scan45Count> Scan45Vertex; std::vector<Scan45Vertex> vertices; //is a Rectnagle(0, 0, 10, 10); Count2 count(1, 0); Count2 ncount(-1, 0); vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, Count2(0, 0), ncount, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), Count2(0, 0), ncount))); vertices.push_back(Scan45Vertex(Point(8,16), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); count = Count2(0, 1); ncount = count.invert(); vertices.push_back(Scan45Vertex(Point(12,8), Scan45Count(count, Count2(0, 0), ncount, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(4,0), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); vertices.push_back(Scan45Vertex(Point(4,16), Scan45Count(ncount, Count2(0, 0), Count2(0, 0), ncount))); sortScan45Vector(vertices); stdcout << "scanning\n"; scan45.scan(result, vertices.begin(), vertices.end()); stdcout << "done scanning\n"; // result size == 24 // result == 0 8 -1 1 // result == 0 8 1 -1 // result == 4 0 1 1 // result == 4 0 2 1 // result == 4 4 2 -1 // result == 4 4 -1 -1 // result == 4 12 1 1 // result == 4 12 2 1 // result == 4 16 2 -1 // result == 4 16 -1 -1 // result == 6 2 1 -1 // result == 6 14 -1 1 // result == 6 2 -1 1 // result == 6 14 1 -1 // result == 8 0 -1 -1 // result == 8 0 2 -1 // result == 8 4 2 1 // result == 8 4 1 1 // result == 8 12 -1 -1 // result == 8 12 2 -1 // result == 8 16 2 1 // result == 8 16 1 1 // result == 12 8 1 -1 // result == 12 8 -1 1 if(result.size() != 24) { //stdcout << "result size == " << result.size() << "\n"; //stdcout << "reference size == " << 24 << "\n"; return false; } stdcout << "done testing Scan45Star1\n"; return true; } template <typename stream_type> static inline bool testScan45Star2(stream_type& stdcout) { stdcout << "testing Scan45Star2\n"; Scan45<Count2, boolean_op_45_output_functor<0> > scan45; std::vector<Vertex45 > result; typedef std::pair<Point, Scan45Count> Scan45Vertex; std::vector<Scan45Vertex> vertices; //is a Rectnagle(0, 0, 10, 10); Count2 count(1, 0); Count2 ncount(-1, 0); vertices.push_back(Scan45Vertex(Point(0,4), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(16,4), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(8,12), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); count = Count2(0, 1); ncount = count.invert(); vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(16,8), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); sortScan45Vector(vertices); stdcout << "scanning\n"; scan45.scan(result, vertices.begin(), vertices.end()); stdcout << "done scanning\n"; // result size == 24 // result == 0 4 0 1 // result == 0 4 1 -1 // result == 0 8 -1 1 // result == 0 8 0 -1 // result == 2 6 1 1 // result == 2 6 -1 -1 // result == 4 4 0 -1 // result == 4 8 0 1 // result == 4 4 -1 1 // result == 4 8 1 -1 // result == 8 0 -1 -1 // result == 8 0 1 1 // result == 8 12 1 1 // result == 8 12 -1 -1 // result == 12 4 1 -1 // result == 12 8 -1 1 // result == 12 4 0 1 // result == 12 8 0 -1 // result == 14 6 -1 -1 // result == 14 6 1 1 // result == 16 4 0 -1 // result == 16 4 -1 1 // result == 16 8 1 -1 // result == 16 8 0 1 if(result.size() != 24) { //std::cout << "result size == " << result.size() << "\n"; //std::cout << "reference size == " << 24 << "\n"; return false; } stdcout << "done testing Scan45Star2\n"; return true; } template <typename stream_type> static inline bool testScan45Star3(stream_type& stdcout) { stdcout << "testing Scan45Star3\n"; Scan45<Count2, boolean_op_45_output_functor<0> > scan45; std::vector<Vertex45 > result; typedef std::pair<Point, Scan45Count> Scan45Vertex; std::vector<Scan45Vertex> vertices; //is a Rectnagle(0, 0, 10, 10); Count2 count(1, 0); Count2 ncount(-1, 0); vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, Count2(0, 0), ncount, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), Count2(0, 0), ncount))); vertices.push_back(Scan45Vertex(Point(8,16), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); vertices.push_back(Scan45Vertex(Point(6,0), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); vertices.push_back(Scan45Vertex(Point(6,14), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); vertices.push_back(Scan45Vertex(Point(12,0), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); vertices.push_back(Scan45Vertex(Point(12,14), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); count = Count2(0, 1); ncount = count.invert(); vertices.push_back(Scan45Vertex(Point(12,8), Scan45Count(count, Count2(0, 0), ncount, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(4,0), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); vertices.push_back(Scan45Vertex(Point(4,16), Scan45Count(ncount, Count2(0, 0), Count2(0, 0), ncount))); sortScan45Vector(vertices); stdcout << "scanning\n"; scan45.scan(result, vertices.begin(), vertices.end()); stdcout << "done scanning\n"; // result size == 28 // result == 0 8 -1 1 // result == 0 8 1 -1 // result == 4 0 1 1 // result == 4 0 2 1 // result == 4 4 2 -1 // result == 4 4 -1 -1 // result == 4 12 1 1 // result == 4 12 2 1 // result == 4 16 2 -1 // result == 4 16 -1 -1 // result == 6 2 1 -1 // result == 6 14 -1 1 // result == 6 0 0 1 // result == 6 0 2 1 // result == 6 2 2 -1 // result == 6 14 1 -1 // result == 8 0 0 -1 // result == 8 0 0 1 // result == 8 14 0 -1 // result == 8 14 2 -1 // result == 8 16 2 1 // result == 8 16 1 1 // result == 12 0 0 -1 // result == 12 0 2 -1 // result == 12 8 2 1 // result == 12 8 2 -1 // result == 12 14 2 1 // result == 12 14 0 1 if(result.size() != 28) { //std::cout << "result size == " << result.size() << "\n"; //std::cout << "reference size == " << 28 << "\n"; return false; } stdcout << "done testing Scan45Star3\n"; return true; } template <typename stream_type> static inline bool testScan45Star4(stream_type& stdcout) { stdcout << "testing Scan45Star4\n"; Scan45<Count2, boolean_op_45_output_functor<0> > scan45; std::vector<Vertex45 > result; typedef std::pair<Point, Scan45Count> Scan45Vertex; std::vector<Scan45Vertex> vertices; //is a Rectnagle(0, 0, 10, 10); Count2 count(1, 0); Count2 ncount(-1, 0); vertices.push_back(Scan45Vertex(Point(0,4), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(16,4), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(8,12), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(0,6), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); vertices.push_back(Scan45Vertex(Point(0,12), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); vertices.push_back(Scan45Vertex(Point(16,6), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); vertices.push_back(Scan45Vertex(Point(16,12), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); count = Count2(0, 1); ncount = count.invert(); vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(16,8), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); sortScan45Vector(vertices); stdcout << "scanning\n"; scan45.scan(result, vertices.begin(), vertices.end()); stdcout << "done scanning\n"; // result size == 28 // result == 0 4 0 1 // result == 0 4 1 -1 // result == 0 6 0 1 // result == 0 6 2 1 // result == 0 8 2 -1 // result == 0 8 2 1 // result == 0 12 2 -1 // result == 0 12 0 -1 // result == 2 6 1 1 // result == 2 6 0 -1 // result == 4 4 0 -1 // result == 4 4 -1 1 // result == 8 12 0 1 // result == 8 0 -1 -1 // result == 8 0 1 1 // result == 8 12 0 -1 // result == 12 4 1 -1 // result == 12 4 0 1 // result == 14 6 -1 -1 // result == 14 6 0 1 // result == 16 4 0 -1 // result == 16 4 -1 1 // result == 16 6 0 -1 // result == 16 6 2 -1 // result == 16 8 2 1 // result == 16 8 2 -1 // result == 16 12 2 1 // result == 16 12 0 1 if(result.size() != 28) { //stdcout << "result size == " << result.size() << "\n"; //stdcout << "reference size == " << 28 << "\n"; return false; } stdcout << "done testing Scan45Star4\n"; return true; } template <typename stream_type> static inline bool testScan45(stream_type& stdcout) { if(!testScan45Rect(stdcout)) return false; if(!testScan45P1(stdcout)) return false; if(!testScan45P2(stdcout)) return false; if(!testScan45And(stdcout)) return false; if(!testScan45Star1(stdcout)) return false; if(!testScan45Star2(stdcout)) return false; if(!testScan45Star3(stdcout)) return false; if(!testScan45Star4(stdcout)) return false; return true; } }; } } #endif detail/voronoi_structures.hpp 0000644 00000025573 15125572616 0012543 0 ustar 00 // Boost.Polygon library detail/voronoi_structures.hpp header file // Copyright Andrii Sydorchuk 2010-2012. // Distributed under 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) // See http://www.boost.org for updates, documentation, and revision history. #ifndef BOOST_POLYGON_DETAIL_VORONOI_STRUCTURES #define BOOST_POLYGON_DETAIL_VORONOI_STRUCTURES #include <list> #include <queue> #include <vector> #include "boost/polygon/voronoi_geometry_type.hpp" namespace boost { namespace polygon { namespace detail { // Cartesian 2D point data structure. template <typename T> class point_2d { public: typedef T coordinate_type; point_2d() {} point_2d(coordinate_type x, coordinate_type y) : x_(x), y_(y) {} bool operator==(const point_2d& that) const { return (this->x_ == that.x()) && (this->y_ == that.y()); } bool operator!=(const point_2d& that) const { return (this->x_ != that.x()) || (this->y_ != that.y()); } coordinate_type x() const { return x_; } coordinate_type y() const { return y_; } point_2d& x(coordinate_type x) { x_ = x; return *this; } point_2d& y(coordinate_type y) { y_ = y; return *this; } private: coordinate_type x_; coordinate_type y_; }; // Site event type. // Occurs when the sweepline sweeps over one of the initial sites: // 1) point site // 2) start-point of the segment site // 3) endpoint of the segment site // Implicit segment direction is defined: the start-point of // the segment compares less than its endpoint. // Each input segment is divided onto two site events: // 1) One going from the start-point to the endpoint // (is_inverse() = false) // 2) Another going from the endpoint to the start-point // (is_inverse() = true) // In beach line data structure segment sites of the first // type precede sites of the second type for the same segment. // Members: // point0_ - point site or segment's start-point // point1_ - segment's endpoint if site is a segment // sorted_index_ - the last bit encodes information if the site is inverse; // the other bits encode site event index among the sorted site events // initial_index_ - site index among the initial input set // Note: for all sites is_inverse_ flag is equal to false by default. template <typename T> class site_event { public: typedef T coordinate_type; typedef point_2d<T> point_type; site_event() : point0_(0, 0), point1_(0, 0), sorted_index_(0), flags_(0) {} site_event(coordinate_type x, coordinate_type y) : point0_(x, y), point1_(x, y), sorted_index_(0), flags_(0) {} explicit site_event(const point_type& point) : point0_(point), point1_(point), sorted_index_(0), flags_(0) {} site_event(coordinate_type x1, coordinate_type y1, coordinate_type x2, coordinate_type y2): point0_(x1, y1), point1_(x2, y2), sorted_index_(0), flags_(0) {} site_event(const point_type& point1, const point_type& point2) : point0_(point1), point1_(point2), sorted_index_(0), flags_(0) {} bool operator==(const site_event& that) const { return (this->point0_ == that.point0_) && (this->point1_ == that.point1_); } bool operator!=(const site_event& that) const { return (this->point0_ != that.point0_) || (this->point1_ != that.point1_); } coordinate_type x() const { return point0_.x(); } coordinate_type y() const { return point0_.y(); } coordinate_type x0() const { return point0_.x(); } coordinate_type y0() const { return point0_.y(); } coordinate_type x1() const { return point1_.x(); } coordinate_type y1() const { return point1_.y(); } const point_type& point0() const { return point0_; } const point_type& point1() const { return point1_; } std::size_t sorted_index() const { return sorted_index_; } site_event& sorted_index(std::size_t index) { sorted_index_ = index; return *this; } std::size_t initial_index() const { return initial_index_; } site_event& initial_index(std::size_t index) { initial_index_ = index; return *this; } bool is_inverse() const { return (flags_ & IS_INVERSE) ? true : false; } site_event& inverse() { std::swap(point0_, point1_); flags_ ^= IS_INVERSE; return *this; } SourceCategory source_category() const { return static_cast<SourceCategory>(flags_ & SOURCE_CATEGORY_BITMASK); } site_event& source_category(SourceCategory source_category) { flags_ |= source_category; return *this; } bool is_point() const { return (point0_.x() == point1_.x()) && (point0_.y() == point1_.y()); } bool is_segment() const { return (point0_.x() != point1_.x()) || (point0_.y() != point1_.y()); } private: enum Bits { IS_INVERSE = 0x20 // 32 }; point_type point0_; point_type point1_; std::size_t sorted_index_; std::size_t initial_index_; std::size_t flags_; }; // Circle event type. // Occurs when the sweepline sweeps over the rightmost point of the Voronoi // circle (with the center at the intersection point of the bisectors). // Circle event is made of the two consecutive nodes in the beach line data // structure. In case another node was inserted during algorithm execution // between the given two nodes circle event becomes inactive. // Variables: // center_x_ - center x-coordinate; // center_y_ - center y-coordinate; // lower_x_ - leftmost x-coordinate; // is_active_ - states whether circle event is still active. // NOTE: lower_y coordinate is always equal to center_y. template <typename T> class circle_event { public: typedef T coordinate_type; circle_event() : is_active_(true) {} circle_event(coordinate_type c_x, coordinate_type c_y, coordinate_type lower_x) : center_x_(c_x), center_y_(c_y), lower_x_(lower_x), is_active_(true) {} coordinate_type x() const { return center_x_; } circle_event& x(coordinate_type center_x) { center_x_ = center_x; return *this; } coordinate_type y() const { return center_y_; } circle_event& y(coordinate_type center_y) { center_y_ = center_y; return *this; } coordinate_type lower_x() const { return lower_x_; } circle_event& lower_x(coordinate_type lower_x) { lower_x_ = lower_x; return *this; } coordinate_type lower_y() const { return center_y_; } bool is_active() const { return is_active_; } circle_event& deactivate() { is_active_ = false; return *this; } private: coordinate_type center_x_; coordinate_type center_y_; coordinate_type lower_x_; bool is_active_; }; // Event queue data structure, holds circle events. // During algorithm run, some of the circle events disappear (become // inactive). Priority queue data structure doesn't support // iterators (there is no direct ability to modify its elements). // Instead list is used to store all the circle events and priority queue // of the iterators to the list elements is used to keep the correct circle // events ordering. template <typename T, typename Predicate> class ordered_queue { public: ordered_queue() {} bool empty() const { return c_.empty(); } const T &top() const { return *c_.top(); } void pop() { list_iterator_type it = c_.top(); c_.pop(); c_list_.erase(it); } T &push(const T &e) { c_list_.push_front(e); c_.push(c_list_.begin()); return c_list_.front(); } void clear() { while (!c_.empty()) c_.pop(); c_list_.clear(); } private: typedef typename std::list<T>::iterator list_iterator_type; struct comparison { bool operator() (const list_iterator_type &it1, const list_iterator_type &it2) const { return cmp_(*it1, *it2); } Predicate cmp_; }; std::priority_queue< list_iterator_type, std::vector<list_iterator_type>, comparison > c_; std::list<T> c_list_; // Disallow copy constructor and operator= ordered_queue(const ordered_queue&); void operator=(const ordered_queue&); }; // Represents a bisector node made by two arcs that correspond to the left // and right sites. Arc is defined as a curve with points equidistant from // the site and from the sweepline. If the site is a point then arc is // a parabola, otherwise it's a line segment. A segment site event will // produce different bisectors based on its direction. // In general case two sites will create two opposite bisectors. That's // why the order of the sites is important to define the unique bisector. // The one site is considered to be newer than the other one if it was // processed by the algorithm later (has greater index). template <typename Site> class beach_line_node_key { public: typedef Site site_type; // Constructs degenerate bisector, used to search an arc that is above // the given site. The input to the constructor is the new site point. explicit beach_line_node_key(const site_type &new_site) : left_site_(new_site), right_site_(new_site) {} // Constructs a new bisector. The input to the constructor is the two // sites that create the bisector. The order of sites is important. beach_line_node_key(const site_type &left_site, const site_type &right_site) : left_site_(left_site), right_site_(right_site) {} const site_type &left_site() const { return left_site_; } site_type &left_site() { return left_site_; } beach_line_node_key& left_site(const site_type &site) { left_site_ = site; return *this; } const site_type &right_site() const { return right_site_; } site_type &right_site() { return right_site_; } beach_line_node_key& right_site(const site_type &site) { right_site_ = site; return *this; } private: site_type left_site_; site_type right_site_; }; // Represents edge data structure from the Voronoi output, that is // associated as a value with beach line bisector in the beach // line. Contains pointer to the circle event in the circle event // queue if the edge corresponds to the right bisector of the circle event. template <typename Edge, typename Circle> class beach_line_node_data { public: explicit beach_line_node_data(Edge* new_edge) : circle_event_(NULL), edge_(new_edge) {} Circle* circle_event() const { return circle_event_; } beach_line_node_data& circle_event(Circle* circle_event) { circle_event_ = circle_event; return *this; } Edge* edge() const { return edge_; } beach_line_node_data& edge(Edge* new_edge) { edge_ = new_edge; return *this; } private: Circle* circle_event_; Edge* edge_; }; } // detail } // polygon } // boost #endif // BOOST_POLYGON_DETAIL_VORONOI_STRUCTURES detail/polygon_90_touch.hpp 0000644 00000042155 15125572616 0011741 0 ustar 00 /* 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_TOUCH_HPP #define BOOST_POLYGON_POLYGON_90_TOUCH_HPP namespace boost { namespace polygon{ template <typename Unit> struct touch_90_operation { typedef interval_data<Unit> Interval; class TouchScanEvent { private: typedef std::map<Unit, std::set<int> > EventData; EventData eventData_; public: // The TouchScanEvent::iterator is a lazy algorithm that accumulates // polygon ids in a set as it is incremented through the // scan event data structure. // The iterator provides a forward iterator semantic only. class iterator { private: typename EventData::const_iterator itr_; std::pair<Interval, std::set<int> > ivlIds_; bool incremented_; public: inline iterator() : itr_(), ivlIds_(), incremented_(false) {} inline iterator(typename EventData::const_iterator itr, Unit prevPos, Unit curPos, const std::set<int>& ivlIds) : itr_(itr), ivlIds_(), incremented_(false) { ivlIds_.second = ivlIds; ivlIds_.first = Interval(prevPos, curPos); } inline iterator(const iterator& that) : itr_(), ivlIds_(), incremented_(false) { (*this) = that; } inline iterator& operator=(const iterator& that) { itr_ = that.itr_; ivlIds_.first = that.ivlIds_.first; ivlIds_.second = that.ivlIds_.second; incremented_ = that.incremented_; return *this; } inline bool operator==(const iterator& that) { return itr_ == that.itr_; } inline bool operator!=(const iterator& that) { return itr_ != that.itr_; } inline iterator& operator++() { //std::cout << "increment\n"; //std::cout << "state\n"; //for(std::set<int>::iterator itr = ivlIds_.second.begin(); itr != ivlIds_.second.end(); ++itr) { // std::cout << (*itr) << " "; //} std::cout << std::endl; //std::cout << "update\n"; for(std::set<int>::const_iterator itr = (*itr_).second.begin(); itr != (*itr_).second.end(); ++itr) { //std::cout << (*itr) << " "; std::set<int>::iterator lb = ivlIds_.second.find(*itr); if(lb != ivlIds_.second.end()) { ivlIds_.second.erase(lb); } else { ivlIds_.second.insert(*itr); } } //std::cout << std::endl; //std::cout << "new state\n"; //for(std::set<int>::iterator itr = ivlIds_.second.begin(); itr != ivlIds_.second.end(); ++itr) { // std::cout << (*itr) << " "; //} std::cout << std::endl; ++itr_; //ivlIds_.first = Interval(ivlIds_.first.get(HIGH), itr_->first); incremented_ = true; return *this; } inline const iterator operator++(int){ iterator tmpItr(*this); ++(*this); return tmpItr; } inline std::pair<Interval, std::set<int> >& operator*() { if(incremented_) ivlIds_.first = Interval(ivlIds_.first.get(HIGH), itr_->first); incremented_ = false; if(ivlIds_.second.empty())(++(*this)); if(incremented_) ivlIds_.first = Interval(ivlIds_.first.get(HIGH), itr_->first); incremented_ = false; return ivlIds_; } }; inline TouchScanEvent() : eventData_() {} template<class iT> inline TouchScanEvent(iT begin, iT end) : eventData_() { for( ; begin != end; ++begin){ insert(*begin); } } inline TouchScanEvent(const TouchScanEvent& that) : eventData_(that.eventData_) {} inline TouchScanEvent& operator=(const TouchScanEvent& that){ eventData_ = that.eventData_; return *this; } //Insert an interval polygon id into the EventData inline void insert(const std::pair<Interval, int>& intervalId){ insert(intervalId.first.low(), intervalId.second); insert(intervalId.first.high(), intervalId.second); } //Insert an position and polygon id into EventData inline void insert(Unit pos, int id) { typename EventData::iterator lb = eventData_.lower_bound(pos); if(lb != eventData_.end() && lb->first == pos) { std::set<int>& mr (lb->second); std::set<int>::iterator mri = mr.find(id); if(mri == mr.end()) { mr.insert(id); } else { mr.erase(id); } } else { lb = eventData_.insert(lb, std::pair<Unit, std::set<int> >(pos, std::set<int>())); (*lb).second.insert(id); } } //merge this scan event with that by inserting its data inline void insert(const TouchScanEvent& that){ typename EventData::const_iterator itr; for(itr = that.eventData_.begin(); itr != that.eventData_.end(); ++itr) { eventData_[(*itr).first].insert(itr->second.begin(), itr->second.end()); } } //Get the begin iterator over event data inline iterator begin() const { //std::cout << "begin\n"; if(eventData_.empty()) return end(); typename EventData::const_iterator itr = eventData_.begin(); Unit pos = itr->first; const std::set<int>& idr = itr->second; ++itr; return iterator(itr, pos, itr->first, idr); } //Get the end iterator over event data inline iterator end() const { return iterator(eventData_.end(), 0, 0, std::set<int>()); } inline void clear() { eventData_.clear(); } inline Interval extents() const { if(eventData_.empty()) return Interval(); return Interval((*(eventData_.begin())).first, (*(eventData_.rbegin())).first); } }; //declaration of a map of scan events by coordinate value used to store all the //polygon data for a single layer input into the scanline algorithm typedef std::pair<std::map<Unit, TouchScanEvent>, std::map<Unit, TouchScanEvent> > TouchSetData; class TouchOp { public: typedef std::map<Unit, std::set<int> > ScanData; typedef std::pair<Unit, std::set<int> > ElementType; protected: ScanData scanData_; typename ScanData::iterator nextItr_; public: inline TouchOp () : scanData_(), nextItr_() { nextItr_ = scanData_.end(); } inline TouchOp (const TouchOp& that) : scanData_(that.scanData_), nextItr_() { nextItr_ = scanData_.begin(); } inline TouchOp& operator=(const TouchOp& that); //moves scanline forward inline void advanceScan() { nextItr_ = scanData_.begin(); } //proceses the given interval and std::set<int> data //the output data structre is a graph, the indicies in the vector correspond to graph nodes, //the integers in the set are vector indicies and are the nodes with which that node shares an edge template <typename graphT> inline void processInterval(graphT& outputContainer, Interval ivl, const std::set<int>& ids, bool leadingEdge) { //print(); typename ScanData::iterator lowItr = lookup_(ivl.low()); typename ScanData::iterator highItr = lookup_(ivl.high()); //std::cout << "Interval: " << ivl << std::endl; //for(std::set<int>::const_iterator itr = ids.begin(); itr != ids.end(); ++itr) // std::cout << (*itr) << " "; //std::cout << std::endl; //add interval to scan data if it is past the end if(lowItr == scanData_.end()) { //std::cout << "case0" << std::endl; lowItr = insert_(ivl.low(), ids); evaluateBorder_(outputContainer, ids, ids); highItr = insert_(ivl.high(), std::set<int>()); return; } //ensure that highItr points to the end of the ivl if(highItr == scanData_.end() || (*highItr).first > ivl.high()) { //std::cout << "case1" << std::endl; //std::cout << highItr->first << std::endl; std::set<int> value = std::set<int>(); if(highItr != scanData_.begin()) { --highItr; //std::cout << highItr->first << std::endl; //std::cout << "high set size " << highItr->second.size() << std::endl; value = highItr->second; } nextItr_ = highItr; highItr = insert_(ivl.high(), value); } else { //evaluate border with next higher interval //std::cout << "case1a" << std::endl; if(leadingEdge)evaluateBorder_(outputContainer, highItr->second, ids); } //split the low interval if needed if(lowItr->first > ivl.low()) { //std::cout << "case2" << std::endl; if(lowItr != scanData_.begin()) { //std::cout << "case3" << std::endl; --lowItr; nextItr_ = lowItr; //std::cout << lowItr->first << " " << lowItr->second.size() << std::endl; lowItr = insert_(ivl.low(), lowItr->second); } else { //std::cout << "case4" << std::endl; nextItr_ = lowItr; lowItr = insert_(ivl.low(), std::set<int>()); } } else { //evaluate border with next higher interval //std::cout << "case2a" << std::endl; typename ScanData::iterator nextLowerItr = lowItr; if(leadingEdge && nextLowerItr != scanData_.begin()){ --nextLowerItr; evaluateBorder_(outputContainer, nextLowerItr->second, ids); } } //std::cout << "low: " << lowItr->first << " high: " << highItr->first << std::endl; //print(); //process scan data intersecting interval for(typename ScanData::iterator itr = lowItr; itr != highItr; ){ //std::cout << "case5" << std::endl; //std::cout << itr->first << std::endl; std::set<int>& beforeIds = itr->second; ++itr; evaluateInterval_(outputContainer, beforeIds, ids, leadingEdge); } //print(); //merge the bottom interval with the one below if they have the same count if(lowItr != scanData_.begin()){ //std::cout << "case6" << std::endl; typename ScanData::iterator belowLowItr = lowItr; --belowLowItr; if(belowLowItr->second == lowItr->second) { //std::cout << "case7" << std::endl; scanData_.erase(lowItr); } } //merge the top interval with the one above if they have the same count if(highItr != scanData_.begin()) { //std::cout << "case8" << std::endl; typename ScanData::iterator beforeHighItr = highItr; --beforeHighItr; if(beforeHighItr->second == highItr->second) { //std::cout << "case9" << std::endl; scanData_.erase(highItr); highItr = beforeHighItr; ++highItr; } } //print(); nextItr_ = highItr; } // inline void print() const { // for(typename ScanData::const_iterator itr = scanData_.begin(); itr != scanData_.end(); ++itr) { // std::cout << itr->first << ": "; // for(std::set<int>::const_iterator sitr = itr->second.begin(); // sitr != itr->second.end(); ++sitr){ // std::cout << *sitr << " "; // } // std::cout << std::endl; // } // } private: inline typename ScanData::iterator lookup_(Unit pos){ if(nextItr_ != scanData_.end() && nextItr_->first >= pos) { return nextItr_; } return nextItr_ = scanData_.lower_bound(pos); } inline typename ScanData::iterator insert_(Unit pos, const std::set<int>& ids){ //std::cout << "inserting " << ids.size() << " ids at: " << pos << std::endl; return nextItr_ = scanData_.insert(nextItr_, std::pair<Unit, std::set<int> >(pos, ids)); } template <typename graphT> inline void evaluateInterval_(graphT& outputContainer, std::set<int>& ids, const std::set<int>& changingIds, bool leadingEdge) { for(std::set<int>::const_iterator ciditr = changingIds.begin(); ciditr != changingIds.end(); ++ciditr){ //std::cout << "evaluateInterval " << (*ciditr) << std::endl; evaluateId_(outputContainer, ids, *ciditr, leadingEdge); } } template <typename graphT> inline void evaluateBorder_(graphT& outputContainer, const std::set<int>& ids, const std::set<int>& changingIds) { for(std::set<int>::const_iterator ciditr = changingIds.begin(); ciditr != changingIds.end(); ++ciditr){ //std::cout << "evaluateBorder " << (*ciditr) << std::endl; evaluateBorderId_(outputContainer, ids, *ciditr); } } template <typename graphT> inline void evaluateBorderId_(graphT& outputContainer, const std::set<int>& ids, int changingId) { for(std::set<int>::const_iterator scanItr = ids.begin(); scanItr != ids.end(); ++scanItr) { //std::cout << "create edge: " << changingId << " " << *scanItr << std::endl; if(changingId != *scanItr){ outputContainer[changingId].insert(*scanItr); outputContainer[*scanItr].insert(changingId); } } } template <typename graphT> inline void evaluateId_(graphT& outputContainer, std::set<int>& ids, int changingId, bool leadingEdge) { //std::cout << "changingId: " << changingId << std::endl; //for( std::set<int>::iterator itr = ids.begin(); itr != ids.end(); ++itr){ // std::cout << *itr << " "; //}std::cout << std::endl; std::set<int>::iterator lb = ids.lower_bound(changingId); if(lb == ids.end() || (*lb) != changingId) { if(leadingEdge) { //std::cout << "insert\n"; //insert and add to output for(std::set<int>::iterator scanItr = ids.begin(); scanItr != ids.end(); ++scanItr) { //std::cout << "create edge: " << changingId << " " << *scanItr << std::endl; if(changingId != *scanItr){ outputContainer[changingId].insert(*scanItr); outputContainer[*scanItr].insert(changingId); } } ids.insert(changingId); } } else { if(!leadingEdge){ //std::cout << "erase\n"; ids.erase(lb); } } } }; template <typename graphT> static inline void processEvent(graphT& outputContainer, TouchOp& op, const TouchScanEvent& data, bool leadingEdge) { for(typename TouchScanEvent::iterator itr = data.begin(); itr != data.end(); ++itr) { //std::cout << "processInterval" << std::endl; op.processInterval(outputContainer, (*itr).first, (*itr).second, leadingEdge); } } template <typename graphT> static inline void performTouch(graphT& outputContainer, const TouchSetData& data) { typename std::map<Unit, TouchScanEvent>::const_iterator leftItr = data.first.begin(); typename std::map<Unit, TouchScanEvent>::const_iterator rightItr = data.second.begin(); typename std::map<Unit, TouchScanEvent>::const_iterator leftEnd = data.first.end(); typename std::map<Unit, TouchScanEvent>::const_iterator rightEnd = data.second.end(); TouchOp op; while(leftItr != leftEnd || rightItr != rightEnd) { //std::cout << "loop" << std::endl; op.advanceScan(); //rightItr cannont be at end if leftItr is not at end if(leftItr != leftEnd && rightItr != rightEnd && leftItr->first <= rightItr->first) { //std::cout << "case1" << std::endl; //std::cout << leftItr ->first << std::endl; processEvent(outputContainer, op, leftItr->second, true); ++leftItr; } else { //std::cout << "case2" << std::endl; //std::cout << rightItr ->first << std::endl; processEvent(outputContainer, op, rightItr->second, false); ++rightItr; } } } template <class iT> static inline void populateTouchSetData(TouchSetData& data, iT beginData, iT endData, int id) { Unit prevPos = ((std::numeric_limits<Unit>::max)()); Unit prevY = prevPos; int count = 0; for(iT itr = beginData; itr != endData; ++itr) { Unit pos = (*itr).first; if(pos != prevPos) { prevPos = pos; prevY = (*itr).second.first; count = (*itr).second.second; continue; } Unit y = (*itr).second.first; if(count != 0 && y != prevY) { std::pair<Interval, int> element(Interval(prevY, y), id); if(count > 0) { data.first[pos].insert(element); } else { data.second[pos].insert(element); } } prevY = y; count += (*itr).second.second; } } static inline void populateTouchSetData(TouchSetData& data, const std::vector<std::pair<Unit, std::pair<Unit, int> > >& inputData, int id) { populateTouchSetData(data, inputData.begin(), inputData.end(), id); } }; } } #endif voronoi_diagram.hpp 0000644 00000046031 15125572616 0010452 0 ustar 00 // Boost.Polygon library voronoi_diagram.hpp header file // Copyright Andrii Sydorchuk 2010-2012. // Distributed under 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) // See http://www.boost.org for updates, documentation, and revision history. #ifndef BOOST_POLYGON_VORONOI_DIAGRAM #define BOOST_POLYGON_VORONOI_DIAGRAM #include <vector> #include <utility> #include "detail/voronoi_ctypes.hpp" #include "detail/voronoi_structures.hpp" #include "voronoi_geometry_type.hpp" namespace boost { namespace polygon { // Forward declarations. template <typename T> class voronoi_edge; // Represents Voronoi cell. // Data members: // 1) index of the source within the initial input set // 2) pointer to the incident edge // 3) mutable color member // Cell may contain point or segment site inside. template <typename T> class voronoi_cell { public: typedef T coordinate_type; typedef std::size_t color_type; typedef voronoi_edge<coordinate_type> voronoi_edge_type; typedef std::size_t source_index_type; typedef SourceCategory source_category_type; voronoi_cell(source_index_type source_index, source_category_type source_category) : source_index_(source_index), incident_edge_(NULL), color_(source_category) {} // Returns true if the cell contains point site, false else. bool contains_point() const { source_category_type source_category = this->source_category(); return belongs(source_category, GEOMETRY_CATEGORY_POINT); } // Returns true if the cell contains segment site, false else. bool contains_segment() const { source_category_type source_category = this->source_category(); return belongs(source_category, GEOMETRY_CATEGORY_SEGMENT); } source_index_type source_index() const { return source_index_; } source_category_type source_category() const { return static_cast<source_category_type>(color_ & SOURCE_CATEGORY_BITMASK); } // Degenerate cells don't have any incident edges. bool is_degenerate() const { return incident_edge_ == NULL; } voronoi_edge_type* incident_edge() { return incident_edge_; } const voronoi_edge_type* incident_edge() const { return incident_edge_; } void incident_edge(voronoi_edge_type* e) { incident_edge_ = e; } color_type color() const { return color_ >> BITS_SHIFT; } void color(color_type color) const { color_ &= BITS_MASK; color_ |= color << BITS_SHIFT; } private: // 5 color bits are reserved. enum Bits { BITS_SHIFT = 0x5, BITS_MASK = 0x1F }; source_index_type source_index_; voronoi_edge_type* incident_edge_; mutable color_type color_; }; // Represents Voronoi vertex. // Data members: // 1) vertex coordinates // 2) pointer to the incident edge // 3) mutable color member template <typename T> class voronoi_vertex { public: typedef T coordinate_type; typedef std::size_t color_type; typedef voronoi_edge<coordinate_type> voronoi_edge_type; voronoi_vertex(const coordinate_type& x, const coordinate_type& y) : x_(x), y_(y), incident_edge_(NULL), color_(0) {} const coordinate_type& x() const { return x_; } const coordinate_type& y() const { return y_; } bool is_degenerate() const { return incident_edge_ == NULL; } voronoi_edge_type* incident_edge() { return incident_edge_; } const voronoi_edge_type* incident_edge() const { return incident_edge_; } void incident_edge(voronoi_edge_type* e) { incident_edge_ = e; } color_type color() const { return color_ >> BITS_SHIFT; } void color(color_type color) const { color_ &= BITS_MASK; color_ |= color << BITS_SHIFT; } private: // 5 color bits are reserved. enum Bits { BITS_SHIFT = 0x5, BITS_MASK = 0x1F }; coordinate_type x_; coordinate_type y_; voronoi_edge_type* incident_edge_; mutable color_type color_; }; // Half-edge data structure. Represents Voronoi edge. // Data members: // 1) pointer to the corresponding cell // 2) pointer to the vertex that is the starting // point of the half-edge // 3) pointer to the twin edge // 4) pointer to the CCW next edge // 5) pointer to the CCW prev edge // 6) mutable color member template <typename T> class voronoi_edge { public: typedef T coordinate_type; typedef voronoi_cell<coordinate_type> voronoi_cell_type; typedef voronoi_vertex<coordinate_type> voronoi_vertex_type; typedef voronoi_edge<coordinate_type> voronoi_edge_type; typedef std::size_t color_type; voronoi_edge(bool is_linear, bool is_primary) : cell_(NULL), vertex_(NULL), twin_(NULL), next_(NULL), prev_(NULL), color_(0) { if (is_linear) color_ |= BIT_IS_LINEAR; if (is_primary) color_ |= BIT_IS_PRIMARY; } voronoi_cell_type* cell() { return cell_; } const voronoi_cell_type* cell() const { return cell_; } void cell(voronoi_cell_type* c) { cell_ = c; } voronoi_vertex_type* vertex0() { return vertex_; } const voronoi_vertex_type* vertex0() const { return vertex_; } void vertex0(voronoi_vertex_type* v) { vertex_ = v; } voronoi_vertex_type* vertex1() { return twin_->vertex0(); } const voronoi_vertex_type* vertex1() const { return twin_->vertex0(); } voronoi_edge_type* twin() { return twin_; } const voronoi_edge_type* twin() const { return twin_; } void twin(voronoi_edge_type* e) { twin_ = e; } voronoi_edge_type* next() { return next_; } const voronoi_edge_type* next() const { return next_; } void next(voronoi_edge_type* e) { next_ = e; } voronoi_edge_type* prev() { return prev_; } const voronoi_edge_type* prev() const { return prev_; } void prev(voronoi_edge_type* e) { prev_ = e; } // Returns a pointer to the rotation next edge // over the starting point of the half-edge. voronoi_edge_type* rot_next() { return prev_->twin(); } const voronoi_edge_type* rot_next() const { return prev_->twin(); } // Returns a pointer to the rotation prev edge // over the starting point of the half-edge. voronoi_edge_type* rot_prev() { return twin_->next(); } const voronoi_edge_type* rot_prev() const { return twin_->next(); } // Returns true if the edge is finite (segment, parabolic arc). // Returns false if the edge is infinite (ray, line). bool is_finite() const { return vertex0() && vertex1(); } // Returns true if the edge is infinite (ray, line). // Returns false if the edge is finite (segment, parabolic arc). bool is_infinite() const { return !vertex0() || !vertex1(); } // Returns true if the edge is linear (segment, ray, line). // Returns false if the edge is curved (parabolic arc). bool is_linear() const { return (color_ & BIT_IS_LINEAR) ? true : false; } // Returns true if the edge is curved (parabolic arc). // Returns false if the edge is linear (segment, ray, line). bool is_curved() const { return (color_ & BIT_IS_LINEAR) ? false : true; } // Returns false if edge goes through the endpoint of the segment. // Returns true else. bool is_primary() const { return (color_ & BIT_IS_PRIMARY) ? true : false; } // Returns true if edge goes through the endpoint of the segment. // Returns false else. bool is_secondary() const { return (color_ & BIT_IS_PRIMARY) ? false : true; } color_type color() const { return color_ >> BITS_SHIFT; } void color(color_type color) const { color_ &= BITS_MASK; color_ |= color << BITS_SHIFT; } private: // 5 color bits are reserved. enum Bits { BIT_IS_LINEAR = 0x1, // linear is opposite to curved BIT_IS_PRIMARY = 0x2, // primary is opposite to secondary BITS_SHIFT = 0x5, BITS_MASK = 0x1F }; voronoi_cell_type* cell_; voronoi_vertex_type* vertex_; voronoi_edge_type* twin_; voronoi_edge_type* next_; voronoi_edge_type* prev_; mutable color_type color_; }; template <typename T> struct voronoi_diagram_traits { typedef T coordinate_type; typedef voronoi_cell<coordinate_type> cell_type; typedef voronoi_vertex<coordinate_type> vertex_type; typedef voronoi_edge<coordinate_type> edge_type; class vertex_equality_predicate_type { public: enum { ULPS = 128 }; bool operator()(const vertex_type& v1, const vertex_type& v2) const { return (ulp_cmp(v1.x(), v2.x(), ULPS) == detail::ulp_comparison<T>::EQUAL) && (ulp_cmp(v1.y(), v2.y(), ULPS) == detail::ulp_comparison<T>::EQUAL); } private: typename detail::ulp_comparison<T> ulp_cmp; }; }; // Voronoi output data structure. // CCW ordering is used on the faces perimeter and around the vertices. template <typename T, typename TRAITS = voronoi_diagram_traits<T> > class voronoi_diagram { public: typedef typename TRAITS::coordinate_type coordinate_type; typedef typename TRAITS::cell_type cell_type; typedef typename TRAITS::vertex_type vertex_type; typedef typename TRAITS::edge_type edge_type; typedef std::vector<cell_type> cell_container_type; typedef typename cell_container_type::const_iterator const_cell_iterator; typedef std::vector<vertex_type> vertex_container_type; typedef typename vertex_container_type::const_iterator const_vertex_iterator; typedef std::vector<edge_type> edge_container_type; typedef typename edge_container_type::const_iterator const_edge_iterator; voronoi_diagram() {} void clear() { cells_.clear(); vertices_.clear(); edges_.clear(); } const cell_container_type& cells() const { return cells_; } const vertex_container_type& vertices() const { return vertices_; } const edge_container_type& edges() const { return edges_; } std::size_t num_cells() const { return cells_.size(); } std::size_t num_edges() const { return edges_.size(); } std::size_t num_vertices() const { return vertices_.size(); } void _reserve(std::size_t num_sites) { cells_.reserve(num_sites); vertices_.reserve(num_sites << 1); edges_.reserve((num_sites << 2) + (num_sites << 1)); } template <typename CT> void _process_single_site(const detail::site_event<CT>& site) { cells_.push_back(cell_type(site.initial_index(), site.source_category())); } // Insert a new half-edge into the output data structure. // Takes as input left and right sites that form a new bisector. // Returns a pair of pointers to a new half-edges. template <typename CT> std::pair<void*, void*> _insert_new_edge( const detail::site_event<CT>& site1, const detail::site_event<CT>& site2) { // Get sites' indexes. std::size_t site_index1 = site1.sorted_index(); std::size_t site_index2 = site2.sorted_index(); bool is_linear = is_linear_edge(site1, site2); bool is_primary = is_primary_edge(site1, site2); // Create a new half-edge that belongs to the first site. edges_.push_back(edge_type(is_linear, is_primary)); edge_type& edge1 = edges_.back(); // Create a new half-edge that belongs to the second site. edges_.push_back(edge_type(is_linear, is_primary)); edge_type& edge2 = edges_.back(); // Add the initial cell during the first edge insertion. if (cells_.empty()) { cells_.push_back(cell_type( site1.initial_index(), site1.source_category())); } // The second site represents a new site during site event // processing. Add a new cell to the cell records. cells_.push_back(cell_type( site2.initial_index(), site2.source_category())); // Set up pointers to cells. edge1.cell(&cells_[site_index1]); edge2.cell(&cells_[site_index2]); // Set up twin pointers. edge1.twin(&edge2); edge2.twin(&edge1); // Return a pointer to the new half-edge. return std::make_pair(&edge1, &edge2); } // Insert a new half-edge into the output data structure with the // start at the point where two previously added half-edges intersect. // Takes as input two sites that create a new bisector, circle event // that corresponds to the intersection point of the two old half-edges, // pointers to those half-edges. Half-edges' direction goes out of the // new Voronoi vertex point. Returns a pair of pointers to a new half-edges. template <typename CT1, typename CT2> std::pair<void*, void*> _insert_new_edge( const detail::site_event<CT1>& site1, const detail::site_event<CT1>& site3, const detail::circle_event<CT2>& circle, void* data12, void* data23) { edge_type* edge12 = static_cast<edge_type*>(data12); edge_type* edge23 = static_cast<edge_type*>(data23); // Add a new Voronoi vertex. vertices_.push_back(vertex_type(circle.x(), circle.y())); vertex_type& new_vertex = vertices_.back(); // Update vertex pointers of the old edges. edge12->vertex0(&new_vertex); edge23->vertex0(&new_vertex); bool is_linear = is_linear_edge(site1, site3); bool is_primary = is_primary_edge(site1, site3); // Add a new half-edge. edges_.push_back(edge_type(is_linear, is_primary)); edge_type& new_edge1 = edges_.back(); new_edge1.cell(&cells_[site1.sorted_index()]); // Add a new half-edge. edges_.push_back(edge_type(is_linear, is_primary)); edge_type& new_edge2 = edges_.back(); new_edge2.cell(&cells_[site3.sorted_index()]); // Update twin pointers. new_edge1.twin(&new_edge2); new_edge2.twin(&new_edge1); // Update vertex pointer. new_edge2.vertex0(&new_vertex); // Update Voronoi prev/next pointers. edge12->prev(&new_edge1); new_edge1.next(edge12); edge12->twin()->next(edge23); edge23->prev(edge12->twin()); edge23->twin()->next(&new_edge2); new_edge2.prev(edge23->twin()); // Return a pointer to the new half-edge. return std::make_pair(&new_edge1, &new_edge2); } void _build() { // Remove degenerate edges. edge_iterator last_edge = edges_.begin(); for (edge_iterator it = edges_.begin(); it != edges_.end(); it += 2) { const vertex_type* v1 = it->vertex0(); const vertex_type* v2 = it->vertex1(); if (v1 && v2 && vertex_equality_predicate_(*v1, *v2)) { remove_edge(&(*it)); } else { if (it != last_edge) { edge_type* e1 = &(*last_edge = *it); edge_type* e2 = &(*(last_edge + 1) = *(it + 1)); e1->twin(e2); e2->twin(e1); if (e1->prev()) { e1->prev()->next(e1); e2->next()->prev(e2); } if (e2->prev()) { e1->next()->prev(e1); e2->prev()->next(e2); } } last_edge += 2; } } edges_.erase(last_edge, edges_.end()); // Set up incident edge pointers for cells and vertices. for (edge_iterator it = edges_.begin(); it != edges_.end(); ++it) { it->cell()->incident_edge(&(*it)); if (it->vertex0()) { it->vertex0()->incident_edge(&(*it)); } } // Remove degenerate vertices. vertex_iterator last_vertex = vertices_.begin(); for (vertex_iterator it = vertices_.begin(); it != vertices_.end(); ++it) { if (it->incident_edge()) { if (it != last_vertex) { *last_vertex = *it; vertex_type* v = &(*last_vertex); edge_type* e = v->incident_edge(); do { e->vertex0(v); e = e->rot_next(); } while (e != v->incident_edge()); } ++last_vertex; } } vertices_.erase(last_vertex, vertices_.end()); // Set up next/prev pointers for infinite edges. if (vertices_.empty()) { if (!edges_.empty()) { // Update prev/next pointers for the line edges. edge_iterator edge_it = edges_.begin(); edge_type* edge1 = &(*edge_it); edge1->next(edge1); edge1->prev(edge1); ++edge_it; edge1 = &(*edge_it); ++edge_it; while (edge_it != edges_.end()) { edge_type* edge2 = &(*edge_it); ++edge_it; edge1->next(edge2); edge1->prev(edge2); edge2->next(edge1); edge2->prev(edge1); edge1 = &(*edge_it); ++edge_it; } edge1->next(edge1); edge1->prev(edge1); } } else { // Update prev/next pointers for the ray edges. for (cell_iterator cell_it = cells_.begin(); cell_it != cells_.end(); ++cell_it) { if (cell_it->is_degenerate()) continue; // Move to the previous edge while // it is possible in the CW direction. edge_type* left_edge = cell_it->incident_edge(); while (left_edge->prev() != NULL) { left_edge = left_edge->prev(); // Terminate if this is not a boundary cell. if (left_edge == cell_it->incident_edge()) break; } if (left_edge->prev() != NULL) continue; edge_type* right_edge = cell_it->incident_edge(); while (right_edge->next() != NULL) right_edge = right_edge->next(); left_edge->prev(right_edge); right_edge->next(left_edge); } } } private: typedef typename cell_container_type::iterator cell_iterator; typedef typename vertex_container_type::iterator vertex_iterator; typedef typename edge_container_type::iterator edge_iterator; typedef typename TRAITS::vertex_equality_predicate_type vertex_equality_predicate_type; template <typename SEvent> bool is_primary_edge(const SEvent& site1, const SEvent& site2) const { bool flag1 = site1.is_segment(); bool flag2 = site2.is_segment(); if (flag1 && !flag2) { return (site1.point0() != site2.point0()) && (site1.point1() != site2.point0()); } if (!flag1 && flag2) { return (site2.point0() != site1.point0()) && (site2.point1() != site1.point0()); } return true; } template <typename SEvent> bool is_linear_edge(const SEvent& site1, const SEvent& site2) const { if (!is_primary_edge(site1, site2)) { return true; } return !(site1.is_segment() ^ site2.is_segment()); } // Remove degenerate edge. void remove_edge(edge_type* edge) { // Update the endpoints of the incident edges to the second vertex. vertex_type* vertex = edge->vertex0(); edge_type* updated_edge = edge->twin()->rot_next(); while (updated_edge != edge->twin()) { updated_edge->vertex0(vertex); updated_edge = updated_edge->rot_next(); } edge_type* edge1 = edge; edge_type* edge2 = edge->twin(); edge_type* edge1_rot_prev = edge1->rot_prev(); edge_type* edge1_rot_next = edge1->rot_next(); edge_type* edge2_rot_prev = edge2->rot_prev(); edge_type* edge2_rot_next = edge2->rot_next(); // Update prev/next pointers for the incident edges. edge1_rot_next->twin()->next(edge2_rot_prev); edge2_rot_prev->prev(edge1_rot_next->twin()); edge1_rot_prev->prev(edge2_rot_next->twin()); edge2_rot_next->twin()->next(edge1_rot_prev); } cell_container_type cells_; vertex_container_type vertices_; edge_container_type edges_; vertex_equality_predicate_type vertex_equality_predicate_; // Disallow copy constructor and operator= voronoi_diagram(const voronoi_diagram&); void operator=(const voronoi_diagram&); }; } // polygon } // boost #endif // BOOST_POLYGON_VORONOI_DIAGRAM polygon_45_set_traits.hpp 0000644 00000014110 15125572616 0011524 0 ustar 00 /* 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_45_SET_TRAITS_HPP #define BOOST_POLYGON_POLYGON_45_SET_TRAITS_HPP namespace boost { namespace polygon{ //default definition of polygon 45 set traits works for any model of polygon 45, polygon 45 with holes or any vector or list thereof template <typename T> struct polygon_45_set_traits { typedef typename get_coordinate_type<T, typename geometry_concept<T>::type >::type coordinate_type; typedef typename get_iterator_type<T>::type iterator_type; typedef T operator_arg_type; static inline iterator_type begin(const T& polygon_set) { return get_iterator_type<T>::begin(polygon_set); } static inline iterator_type end(const T& polygon_set) { return get_iterator_type<T>::end(polygon_set); } static inline bool clean(const T& ) { return false; } static inline bool sorted(const T& ) { return false; } }; template <typename T> struct is_45_polygonal_concept { typedef gtl_no type; }; template <> struct is_45_polygonal_concept<polygon_45_concept> { typedef gtl_yes type; }; template <> struct is_45_polygonal_concept<polygon_45_with_holes_concept> { typedef gtl_yes type; }; template <> struct is_45_polygonal_concept<polygon_45_set_concept> { typedef gtl_yes type; }; template <typename T> struct is_polygon_45_set_type { typedef typename is_45_polygonal_concept<typename geometry_concept<T>::type>::type type; }; template <typename T> struct is_polygon_45_set_type<std::list<T> > { typedef typename gtl_or< typename is_45_polygonal_concept<typename geometry_concept<std::list<T> >::type>::type, typename is_45_polygonal_concept<typename geometry_concept<typename std::list<T>::value_type>::type>::type>::type type; }; template <typename T> struct is_polygon_45_set_type<std::vector<T> > { typedef typename gtl_or< typename is_45_polygonal_concept<typename geometry_concept<std::vector<T> >::type>::type, typename is_45_polygonal_concept<typename geometry_concept<typename std::vector<T>::value_type>::type>::type>::type type; }; template <typename T> struct is_mutable_polygon_45_set_type { typedef typename gtl_same_type<polygon_45_set_concept, typename geometry_concept<T>::type>::type type; }; template <typename T> struct is_mutable_polygon_45_set_type<std::list<T> > { typedef typename gtl_or< typename gtl_same_type<polygon_45_set_concept, typename geometry_concept<std::list<T> >::type>::type, typename is_45_polygonal_concept<typename geometry_concept<typename std::list<T>::value_type>::type>::type>::type type; }; template <typename T> struct is_mutable_polygon_45_set_type<std::vector<T> > { typedef typename gtl_or< typename gtl_same_type<polygon_45_set_concept, typename geometry_concept<std::vector<T> >::type>::type, typename is_45_polygonal_concept<typename geometry_concept<typename std::vector<T>::value_type>::type>::type>::type type; }; template <typename T> bool fracture_holes_45_by_concept() { return false; } template <> inline bool fracture_holes_45_by_concept<polygon_45_concept>() { return true; } template <typename T, typename iT> void get_45_polygons_T(T& t, iT begin, iT end) { typedef typename polygon_45_set_traits<T>::coordinate_type Unit; typedef typename geometry_concept<typename T::value_type>::type CType; typename polygon_45_formation<Unit>::Polygon45Formation pf(fracture_holes_45_by_concept<CType>()); //std::cout << "FORMING POLYGONS\n"; pf.scan(t, begin, end); } template <typename T> struct polygon_45_set_mutable_traits {}; template <typename T> struct polygon_45_set_mutable_traits<std::list<T> > { template <typename input_iterator_type> static inline void set(std::list<T>& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { polygon_set.clear(); polygon_45_set_data<typename polygon_45_set_traits<std::list<T> >::coordinate_type> ps; ps.reserve(std::distance(input_begin, input_end)); ps.insert(input_begin, input_end); ps.sort(); ps.clean(); get_45_polygons_T(polygon_set, ps.begin(), ps.end()); } }; template <typename T> struct polygon_45_set_mutable_traits<std::vector<T> > { template <typename input_iterator_type> static inline void set(std::vector<T>& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { polygon_set.clear(); size_t num_ele = std::distance(input_begin, input_end); polygon_set.reserve(num_ele); polygon_45_set_data<typename polygon_45_set_traits<std::list<T> >::coordinate_type> ps; ps.reserve(num_ele); ps.insert(input_begin, input_end); ps.sort(); ps.clean(); get_45_polygons_T(polygon_set, ps.begin(), ps.end()); } }; template <typename T> struct polygon_45_set_mutable_traits<polygon_45_set_data<T> > { template <typename input_iterator_type> static inline void set(polygon_45_set_data<T>& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { polygon_set.set(input_begin, input_end); } }; template <typename T> struct polygon_45_set_traits<polygon_45_set_data<T> > { typedef typename polygon_45_set_data<T>::coordinate_type coordinate_type; typedef typename polygon_45_set_data<T>::iterator_type iterator_type; typedef typename polygon_45_set_data<T>::operator_arg_type operator_arg_type; static inline iterator_type begin(const polygon_45_set_data<T>& polygon_set) { return polygon_set.begin(); } static inline iterator_type end(const polygon_45_set_data<T>& polygon_set) { return polygon_set.end(); } static inline bool clean(const polygon_45_set_data<T>& polygon_set) { polygon_set.clean(); return true; } static inline bool sorted(const polygon_45_set_data<T>& polygon_set) { polygon_set.sort(); return true; } }; } } #endif polygon_set_data.hpp 0000644 00000116473 15125572616 0010636 0 ustar 00 /* 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_SET_DATA_HPP #define BOOST_POLYGON_POLYGON_SET_DATA_HPP #include "polygon_45_set_data.hpp" #include "polygon_45_set_concept.hpp" #include "polygon_traits.hpp" #include "detail/polygon_arbitrary_formation.hpp" namespace boost { namespace polygon { // utility function to round coordinate types down // rounds down for both negative and positive numbers // intended really for integer type T (does not make sense for float) template <typename T> static inline T round_down(double val) { T rounded_val = (T)(val); if(val < (double)rounded_val) --rounded_val; return rounded_val; } template <typename T> static inline point_data<T> round_down(point_data<double> v) { return point_data<T>(round_down<T>(v.x()),round_down<T>(v.y())); } //foward declare view template <typename ltype, typename rtype, int op_type> class polygon_set_view; template <typename T> class polygon_set_data { public: typedef T coordinate_type; typedef point_data<T> point_type; typedef std::pair<point_type, point_type> edge_type; typedef std::pair<edge_type, int> element_type; typedef std::vector<element_type> value_type; typedef typename value_type::const_iterator iterator_type; typedef polygon_set_data operator_arg_type; // default constructor inline polygon_set_data() : data_(), dirty_(false), unsorted_(false), is_45_(true) {} // constructor from an iterator pair over edge data template <typename iT> inline polygon_set_data(iT input_begin, iT input_end) : data_(), dirty_(false), unsorted_(false), is_45_(true) { for( ; input_begin != input_end; ++input_begin) { insert(*input_begin); } } // copy constructor inline polygon_set_data(const polygon_set_data& that) : data_(that.data_), dirty_(that.dirty_), unsorted_(that.unsorted_), is_45_(that.is_45_) {} // copy constructor template <typename ltype, typename rtype, int op_type> inline polygon_set_data(const polygon_set_view<ltype, rtype, op_type>& that); // destructor inline ~polygon_set_data() {} // assignement operator inline polygon_set_data& operator=(const polygon_set_data& that) { if(this == &that) return *this; data_ = that.data_; dirty_ = that.dirty_; unsorted_ = that.unsorted_; is_45_ = that.is_45_; return *this; } template <typename ltype, typename rtype, int op_type> inline polygon_set_data& operator=(const polygon_set_view<ltype, rtype, op_type>& geometry) { (*this) = geometry.value(); dirty_ = false; unsorted_ = false; return *this; } template <typename geometry_object> inline polygon_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, bool is_hole = false) { if(input_begin == input_end || (!data_.empty() && &(*input_begin) == &(*(data_.begin())))) return; dirty_ = true; unsorted_ = true; while(input_begin != input_end) { insert(*input_begin, is_hole); ++input_begin; } } // insert iterator range template <typename iT> inline void insert(iT input_begin, iT input_end, bool is_hole = false) { if(input_begin == input_end) return; for(; input_begin != input_end; ++input_begin) { insert(*input_begin, is_hole); } } template <typename geometry_type> inline void insert(const geometry_type& geometry_object, bool is_hole = false) { insert(geometry_object, is_hole, typename geometry_concept<geometry_type>::type()); } template <typename polygon_type> inline void insert(const polygon_type& polygon_object, bool is_hole, polygon_concept ) { insert_vertex_sequence(begin_points(polygon_object), end_points(polygon_object), winding(polygon_object), is_hole); } inline void insert(const polygon_set_data& ps, bool is_hole = false) { insert(ps.data_.begin(), ps.data_.end(), is_hole); } template <typename polygon_45_set_type> inline void insert(const polygon_45_set_type& ps, bool is_hole, polygon_45_set_concept) { std::vector<polygon_45_with_holes_data<typename polygon_45_set_traits<polygon_45_set_type>::coordinate_type> > polys; assign(polys, ps); insert(polys.begin(), polys.end(), is_hole); } template <typename polygon_90_set_type> inline void insert(const polygon_90_set_type& ps, bool is_hole, polygon_90_set_concept) { std::vector<polygon_90_with_holes_data<typename polygon_90_set_traits<polygon_90_set_type>::coordinate_type> > polys; assign(polys, ps); insert(polys.begin(), polys.end(), is_hole); } template <typename polygon_type> inline void insert(const polygon_type& polygon_object, bool is_hole, polygon_45_concept ) { insert(polygon_object, is_hole, polygon_concept()); } template <typename polygon_type> inline void insert(const polygon_type& polygon_object, bool is_hole, polygon_90_concept ) { insert(polygon_object, is_hole, polygon_concept()); } template <typename polygon_with_holes_type> inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, polygon_with_holes_concept ) { insert(polygon_with_holes_object, is_hole, polygon_concept()); for(typename polygon_with_holes_traits<polygon_with_holes_type>::iterator_holes_type itr = begin_holes(polygon_with_holes_object); itr != end_holes(polygon_with_holes_object); ++itr) { insert(*itr, !is_hole, polygon_concept()); } } template <typename polygon_with_holes_type> inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, polygon_45_with_holes_concept ) { insert(polygon_with_holes_object, is_hole, polygon_with_holes_concept()); } template <typename polygon_with_holes_type> inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, polygon_90_with_holes_concept ) { insert(polygon_with_holes_object, is_hole, polygon_with_holes_concept()); } template <typename rectangle_type> inline void insert(const rectangle_type& rectangle_object, bool is_hole, rectangle_concept ) { polygon_90_data<coordinate_type> poly; assign(poly, rectangle_object); insert(poly, is_hole, polygon_concept()); } inline void insert_clean(const element_type& edge, bool is_hole = false) { if( ! scanline_base<coordinate_type>::is_45_degree(edge.first) && ! scanline_base<coordinate_type>::is_horizontal(edge.first) && ! scanline_base<coordinate_type>::is_vertical(edge.first) ) is_45_ = false; data_.push_back(edge); if(data_.back().first.second < data_.back().first.first) { std::swap(data_.back().first.second, data_.back().first.first); data_.back().second *= -1; } if(is_hole) data_.back().second *= -1; } inline void insert(const element_type& edge, bool is_hole = false) { insert_clean(edge, is_hole); dirty_ = true; unsorted_ = true; } template <class iT> inline void insert_vertex_sequence(iT begin_vertex, iT end_vertex, direction_1d winding, bool is_hole) { if (begin_vertex == end_vertex) { // No edges to insert. return; } // Current edge endpoints. iT vertex0 = begin_vertex; iT vertex1 = begin_vertex; if (++vertex1 == end_vertex) { // No edges to insert. return; } int wmultiplier = (winding == COUNTERCLOCKWISE) ? 1 : -1; if (is_hole) { wmultiplier = -wmultiplier; } dirty_ = true; unsorted_ = true; while (vertex0 != end_vertex) { point_type p0, p1; assign(p0, *vertex0); assign(p1, *vertex1); if (p0 != p1) { int hmultiplier = (p0.get(HORIZONTAL) == p1.get(HORIZONTAL)) ? -1 : 1; element_type elem(edge_type(p0, p1), hmultiplier * wmultiplier); insert_clean(elem); } ++vertex0; ++vertex1; if (vertex1 == end_vertex) { vertex1 = begin_vertex; } } } template <typename output_container> inline void get(output_container& output) const { get_dispatch(output, typename geometry_concept<typename output_container::value_type>::type()); } // append to the container cT with polygons of three or four verticies // slicing orientation is vertical template <class cT> void get_trapezoids(cT& container) const { clean(); trapezoid_arbitrary_formation<coordinate_type> pf; typedef typename polygon_arbitrary_formation<coordinate_type>::vertex_half_edge vertex_half_edge; std::vector<vertex_half_edge> data; for(iterator_type itr = data_.begin(); itr != data_.end(); ++itr){ data.push_back(vertex_half_edge((*itr).first.first, (*itr).first.second, (*itr).second)); data.push_back(vertex_half_edge((*itr).first.second, (*itr).first.first, -1 * (*itr).second)); } polygon_sort(data.begin(), data.end()); pf.scan(container, data.begin(), data.end()); //std::cout << "DONE FORMING POLYGONS\n"; } // append to the container cT with polygons of three or four verticies template <class cT> void get_trapezoids(cT& container, orientation_2d slicing_orientation) const { if(slicing_orientation == VERTICAL) { get_trapezoids(container); } else { polygon_set_data<T> ps(*this); ps.transform(axis_transformation(axis_transformation::SWAP_XY)); cT result; ps.get_trapezoids(result); for(typename cT::iterator itr = result.begin(); itr != result.end(); ++itr) { ::boost::polygon::transform(*itr, axis_transformation(axis_transformation::SWAP_XY)); } container.insert(container.end(), result.begin(), result.end()); } } // equivalence operator inline bool operator==(const polygon_set_data& p) const; // inequivalence operator inline bool operator!=(const polygon_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_set_data inline void clear() { data_.clear(); dirty_ = unsorted_ = false; } // find out if Polygon set is empty inline bool empty() const { 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_; } void clean() const; void sort() const{ if(unsorted_) { polygon_sort(data_.begin(), data_.end()); unsorted_ = false; } } template <typename input_iterator_type> void set(input_iterator_type input_begin, input_iterator_type input_end) { clear(); reserve(std::distance(input_begin,input_end)); insert(input_begin, input_end); dirty_ = true; unsorted_ = true; } void set(const value_type& value) { data_ = value; dirty_ = true; unsorted_ = true; } template <typename rectangle_type> bool extents(rectangle_type& rect) { clean(); if(empty()) return false; bool first_iteration = true; for(iterator_type itr = begin(); itr != end(); ++itr) { rectangle_type edge_box; set_points(edge_box, (*itr).first.first, (*itr).first.second); if(first_iteration) rect = edge_box; else encompass(rect, edge_box); first_iteration = false; } return true; } inline polygon_set_data& resize(coordinate_type resizing, bool corner_fill_arc = false, unsigned int num_circle_segments=0); template <typename transform_type> inline polygon_set_data& transform(const transform_type& tr) { std::vector<polygon_with_holes_data<T> > polys; get(polys); clear(); for(std::size_t i = 0 ; i < polys.size(); ++i) { ::boost::polygon::transform(polys[i], tr); insert(polys[i]); } unsorted_ = true; dirty_ = true; return *this; } inline polygon_set_data& scale_up(typename coordinate_traits<coordinate_type>::unsigned_area_type factor) { for(typename value_type::iterator itr = data_.begin(); itr != data_.end(); ++itr) { ::boost::polygon::scale_up((*itr).first.first, factor); ::boost::polygon::scale_up((*itr).first.second, factor); } return *this; } inline polygon_set_data& scale_down(typename coordinate_traits<coordinate_type>::unsigned_area_type factor) { for(typename value_type::iterator itr = data_.begin(); itr != data_.end(); ++itr) { bool vb = (*itr).first.first.x() == (*itr).first.second.x(); ::boost::polygon::scale_down((*itr).first.first, factor); ::boost::polygon::scale_down((*itr).first.second, factor); bool va = (*itr).first.first.x() == (*itr).first.second.x(); if(!vb && va) { (*itr).second *= -1; } } unsorted_ = true; dirty_ = true; return *this; } template <typename scaling_type> inline polygon_set_data& scale(polygon_set_data&, const scaling_type& scaling) { for(typename value_type::iterator itr = begin(); itr != end(); ++itr) { bool vb = (*itr).first.first.x() == (*itr).first.second.x(); ::boost::polygon::scale((*itr).first.first, scaling); ::boost::polygon::scale((*itr).first.second, scaling); bool va = (*itr).first.first.x() == (*itr).first.second.x(); if(!vb && va) { (*itr).second *= -1; } } unsorted_ = true; dirty_ = true; return *this; } static inline void compute_offset_edge(point_data<long double>& pt1, point_data<long double>& pt2, const point_data<long double>& prev_pt, const point_data<long double>& current_pt, long double distance, int multiplier) { long double dx = current_pt.x() - prev_pt.x(); long double dy = current_pt.y() - prev_pt.y(); long double edge_length = std::sqrt(dx*dx + dy*dy); long double dnx = dy; long double dny = -dx; dnx = dnx * (long double)distance / edge_length; dny = dny * (long double)distance / edge_length; pt1.x(prev_pt.x() + (long double)dnx * (long double)multiplier); pt2.x(current_pt.x() + (long double)dnx * (long double)multiplier); pt1.y(prev_pt.y() + (long double)dny * (long double)multiplier); pt2.y(current_pt.y() + (long double)dny * (long double)multiplier); } static inline void modify_pt(point_data<coordinate_type>& pt, const point_data<coordinate_type>& prev_pt, const point_data<coordinate_type>& current_pt, const point_data<coordinate_type>& next_pt, coordinate_type distance, coordinate_type multiplier) { std::pair<point_data<long double>, point_data<long double> > he1, he2; he1.first.x((long double)(prev_pt.x())); he1.first.y((long double)(prev_pt.y())); he1.second.x((long double)(current_pt.x())); he1.second.y((long double)(current_pt.y())); he2.first.x((long double)(current_pt.x())); he2.first.y((long double)(current_pt.y())); he2.second.x((long double)(next_pt.x())); he2.second.y((long double)(next_pt.y())); compute_offset_edge(he1.first, he1.second, prev_pt, current_pt, distance, multiplier); compute_offset_edge(he2.first, he2.second, current_pt, next_pt, distance, multiplier); typedef scanline_base<long double>::compute_intersection_pack pack; point_data<long double> rpt; point_data<long double> bisectorpt((he1.second.x()+he2.first.x())/2, (he1.second.y()+he2.first.y())/2); point_data<long double> orig_pt((long double)pt.x(), (long double)pt.y()); if(euclidean_distance(bisectorpt, orig_pt) < distance/2) { if(!pack::compute_lazy_intersection(rpt, he1, he2, true, false)) { rpt = he1.second; //colinear offset edges use shared point } } else { if(!pack::compute_lazy_intersection(rpt, he1, std::pair<point_data<long double>, point_data<long double> >(orig_pt, bisectorpt), true, false)) { rpt = he1.second; //colinear offset edges use shared point } } pt.x((coordinate_type)(std::floor(rpt.x()+0.5))); pt.y((coordinate_type)(std::floor(rpt.y()+0.5))); } static void resize_poly_up(std::vector<point_data<coordinate_type> >& poly, coordinate_type distance, coordinate_type multiplier) { point_data<coordinate_type> first_pt = poly[0]; point_data<coordinate_type> second_pt = poly[1]; point_data<coordinate_type> prev_pt = poly[0]; point_data<coordinate_type> current_pt = poly[1]; for(std::size_t i = 2; i < poly.size()-1; ++i) { point_data<coordinate_type> next_pt = poly[i]; modify_pt(poly[i-1], prev_pt, current_pt, next_pt, distance, multiplier); prev_pt = current_pt; current_pt = next_pt; } point_data<coordinate_type> next_pt = first_pt; modify_pt(poly[poly.size()-2], prev_pt, current_pt, next_pt, distance, multiplier); prev_pt = current_pt; current_pt = next_pt; next_pt = second_pt; modify_pt(poly[0], prev_pt, current_pt, next_pt, distance, multiplier); poly.back() = poly.front(); } static bool resize_poly_down(std::vector<point_data<coordinate_type> >& poly, coordinate_type distance, coordinate_type multiplier) { std::vector<point_data<coordinate_type> > orig_poly(poly); rectangle_data<coordinate_type> extents_rectangle; set_points(extents_rectangle, poly[0], poly[0]); point_data<coordinate_type> first_pt = poly[0]; point_data<coordinate_type> second_pt = poly[1]; point_data<coordinate_type> prev_pt = poly[0]; point_data<coordinate_type> current_pt = poly[1]; encompass(extents_rectangle, current_pt); for(std::size_t i = 2; i < poly.size()-1; ++i) { point_data<coordinate_type> next_pt = poly[i]; encompass(extents_rectangle, next_pt); modify_pt(poly[i-1], prev_pt, current_pt, next_pt, distance, multiplier); prev_pt = current_pt; current_pt = next_pt; } if(delta(extents_rectangle, HORIZONTAL) <= std::abs(2*distance)) return false; if(delta(extents_rectangle, VERTICAL) <= std::abs(2*distance)) return false; point_data<coordinate_type> next_pt = first_pt; modify_pt(poly[poly.size()-2], prev_pt, current_pt, next_pt, distance, multiplier); prev_pt = current_pt; current_pt = next_pt; next_pt = second_pt; modify_pt(poly[0], prev_pt, current_pt, next_pt, distance, multiplier); poly.back() = poly.front(); //if the line segments formed between orignial and new points cross for an edge that edge inverts //if all edges invert the polygon should be discarded //if even one edge does not invert return true because the polygon is valid bool non_inverting_edge = false; for(std::size_t i = 1; i < poly.size(); ++i) { std::pair<point_data<coordinate_type>, point_data<coordinate_type> > he1(poly[i], orig_poly[i]), he2(poly[i-1], orig_poly[i-1]); if(!scanline_base<coordinate_type>::intersects(he1, he2)) { non_inverting_edge = true; break; } } return non_inverting_edge; } polygon_set_data& bloat(typename coordinate_traits<coordinate_type>::unsigned_area_type distance) { std::list<polygon_with_holes_data<coordinate_type> > polys; get(polys); clear(); for(typename std::list<polygon_with_holes_data<coordinate_type> >::iterator itr = polys.begin(); itr != polys.end(); ++itr) { resize_poly_up((*itr).self_.coords_, (coordinate_type)distance, (coordinate_type)1); insert_vertex_sequence((*itr).self_.begin(), (*itr).self_.end(), COUNTERCLOCKWISE, false); //inserts without holes for(typename std::list<polygon_data<coordinate_type> >::iterator itrh = (*itr).holes_.begin(); itrh != (*itr).holes_.end(); ++itrh) { if(resize_poly_down((*itrh).coords_, (coordinate_type)distance, (coordinate_type)1)) { insert_vertex_sequence((*itrh).coords_.begin(), (*itrh).coords_.end(), CLOCKWISE, true); } } } return *this; } polygon_set_data& shrink(typename coordinate_traits<coordinate_type>::unsigned_area_type distance) { std::list<polygon_with_holes_data<coordinate_type> > polys; get(polys); clear(); for(typename std::list<polygon_with_holes_data<coordinate_type> >::iterator itr = polys.begin(); itr != polys.end(); ++itr) { if(resize_poly_down((*itr).self_.coords_, (coordinate_type)distance, (coordinate_type)-1)) { insert_vertex_sequence((*itr).self_.begin(), (*itr).self_.end(), COUNTERCLOCKWISE, false); //inserts without holes for(typename std::list<polygon_data<coordinate_type> >::iterator itrh = (*itr).holes_.begin(); itrh != (*itr).holes_.end(); ++itrh) { resize_poly_up((*itrh).coords_, (coordinate_type)distance, (coordinate_type)-1); insert_vertex_sequence((*itrh).coords_.begin(), (*itrh).coords_.end(), CLOCKWISE, true); } } } return *this; } // TODO:: should be private template <typename geometry_type> inline polygon_set_data& insert_with_resize(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc=false, unsigned int num_circle_segments=0, bool hole = false) { return insert_with_resize_dispatch(poly, resizing, corner_fill_arc, num_circle_segments, hole, typename geometry_concept<geometry_type>::type()); } template <typename geometry_type> inline polygon_set_data& insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole, polygon_with_holes_concept) { insert_with_resize_dispatch(poly, resizing, corner_fill_arc, num_circle_segments, hole, polygon_concept()); for(typename polygon_with_holes_traits<geometry_type>::iterator_holes_type itr = begin_holes(poly); itr != end_holes(poly); ++itr) { insert_with_resize_dispatch(*itr, resizing, corner_fill_arc, num_circle_segments, !hole, polygon_concept()); } return *this; } template <typename geometry_type> inline polygon_set_data& insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole, polygon_concept) { if (resizing==0) return *this; // one dimensional used to store CCW/CW flag //direction_1d wdir = winding(poly); // LOW==CLOCKWISE just faster to type // so > 0 is CCW //int multiplier = wdir == LOW ? -1 : 1; //std::cout<<" multiplier : "<<multiplier<<std::endl; //if(hole) resizing *= -1; direction_1d resize_wdir = resizing>0?COUNTERCLOCKWISE:CLOCKWISE; typedef typename polygon_data<T>::iterator_type piterator; piterator first, second, third, end, real_end; real_end = end_points(poly); third = begin_points(poly); first = third; if(first == real_end) return *this; ++third; if(third == real_end) return *this; second = end = third; ++third; if(third == real_end) return *this; // for 1st corner std::vector<point_data<T> > first_pts; std::vector<point_data<T> > all_pts; direction_1d first_wdir = CLOCKWISE; // for all corners polygon_set_data<T> sizingSet; bool sizing_sign = resizing<0; bool prev_concave = true; point_data<T> prev_point; //int iCtr=0; //insert minkofski shapes on edges and corners do { // REAL WORK IS HERE //first, second and third point to points in correct CCW order // check if convex or concave case point_data<coordinate_type> normal1( second->y()-first->y(), first->x()-second->x()); point_data<coordinate_type> normal2( third->y()-second->y(), second->x()-third->x()); double direction = normal1.x()*normal2.y()- normal2.x()*normal1.y(); bool convex = direction>0; bool treat_as_concave = !convex; if(sizing_sign) treat_as_concave = convex; point_data<double> v; assign(v, normal1); double s2 = (v.x()*v.x()+v.y()*v.y()); double s = std::sqrt(s2)/resizing; v = point_data<double>(v.x()/s,v.y()/s); point_data<T> curr_prev; if (prev_concave) //TODO missing round_down() curr_prev = point_data<T>(first->x()+v.x(),first->y()+v.y()); else curr_prev = prev_point; // around concave corners - insert rectangle // if previous corner is concave it's point info may be ignored if ( treat_as_concave) { std::vector<point_data<T> > pts; pts.push_back(point_data<T>(second->x()+v.x(),second->y()+v.y())); pts.push_back(*second); pts.push_back(*first); pts.push_back(point_data<T>(curr_prev)); if (first_pts.size()){ sizingSet.insert_vertex_sequence(pts.begin(),pts.end(), resize_wdir,false); }else { first_pts=pts; first_wdir = resize_wdir; } } else { // add either intersection_quad or pie_shape, based on corner_fill_arc option // for convex corner (convexity depends on sign of resizing, whether we shrink or grow) std::vector< std::vector<point_data<T> > > pts; direction_1d winding; winding = convex?COUNTERCLOCKWISE:CLOCKWISE; if (make_resizing_vertex_list(pts, curr_prev, prev_concave, *first, *second, *third, resizing , num_circle_segments, corner_fill_arc)) { if (first_pts.size()) { for (int i=0; i<pts.size(); i++) { sizingSet.insert_vertex_sequence(pts[i].begin(),pts[i].end(),winding,false); } } else { first_pts = pts[0]; first_wdir = resize_wdir; for (int i=1; i<pts.size(); i++) { sizingSet.insert_vertex_sequence(pts[i].begin(),pts[i].end(),winding,false); } } prev_point = curr_prev; } else { treat_as_concave = true; } } prev_concave = treat_as_concave; first = second; second = third; ++third; if(third == real_end) { third = begin_points(poly); if(*second == *third) { ++third; //skip first point if it is duplicate of last point } } } while(second != end); // handle insertion of first point if (!prev_concave) { first_pts[first_pts.size()-1]=prev_point; } sizingSet.insert_vertex_sequence(first_pts.begin(),first_pts.end(),first_wdir,false); polygon_set_data<coordinate_type> tmp; //insert original shape tmp.insert(poly, false, polygon_concept()); if((resizing < 0) ^ hole) tmp -= sizingSet; else tmp += sizingSet; //tmp.clean(); insert(tmp, hole); return (*this); } inline polygon_set_data& interact(const polygon_set_data& that); inline bool downcast(polygon_45_set_data<coordinate_type>& result) const { if(!is_45_) return false; for(iterator_type itr = begin(); itr != end(); ++itr) { const element_type& elem = *itr; int count = elem.second; int rise = 1; //up sloping 45 if(scanline_base<coordinate_type>::is_horizontal(elem.first)) rise = 0; else if(scanline_base<coordinate_type>::is_vertical(elem.first)) rise = 2; else { if(!scanline_base<coordinate_type>::is_45_degree(elem.first)) { is_45_ = false; return false; //consider throwing because is_45_ has be be wrong } if(elem.first.first.y() > elem.first.second.y()) rise = -1; //down sloping 45 } typename polygon_45_set_data<coordinate_type>::Vertex45Compact vertex(elem.first.first, rise, count); result.insert(vertex); typename polygon_45_set_data<coordinate_type>::Vertex45Compact vertex2(elem.first.second, rise, -count); result.insert(vertex2); } return true; } inline GEOMETRY_CONCEPT_ID concept_downcast() const { typedef typename coordinate_traits<coordinate_type>::coordinate_difference delta_type; bool is_45 = false; for(iterator_type itr = begin(); itr != end(); ++itr) { const element_type& elem = *itr; delta_type h_delta = euclidean_distance(elem.first.first, elem.first.second, HORIZONTAL); delta_type v_delta = euclidean_distance(elem.first.first, elem.first.second, VERTICAL); if(h_delta != 0 || v_delta != 0) { //neither delta is zero and the edge is not MANHATTAN if(v_delta != h_delta && v_delta != -h_delta) return POLYGON_SET_CONCEPT; else is_45 = true; } } if(is_45) return POLYGON_45_SET_CONCEPT; return POLYGON_90_SET_CONCEPT; } private: mutable value_type data_; mutable bool dirty_; mutable bool unsorted_; mutable bool is_45_; private: //functions template <typename output_container> void get_dispatch(output_container& output, polygon_concept tag) const { get_fracture(output, true, tag); } template <typename output_container> void get_dispatch(output_container& output, polygon_with_holes_concept tag) const { get_fracture(output, false, tag); } template <typename output_container, typename concept_type> void get_fracture(output_container& container, bool fracture_holes, concept_type ) const { clean(); polygon_arbitrary_formation<coordinate_type> pf(fracture_holes); typedef typename polygon_arbitrary_formation<coordinate_type>::vertex_half_edge vertex_half_edge; std::vector<vertex_half_edge> data; for(iterator_type itr = data_.begin(); itr != data_.end(); ++itr){ data.push_back(vertex_half_edge((*itr).first.first, (*itr).first.second, (*itr).second)); data.push_back(vertex_half_edge((*itr).first.second, (*itr).first.first, -1 * (*itr).second)); } polygon_sort(data.begin(), data.end()); pf.scan(container, data.begin(), data.end()); } }; struct polygon_set_concept; template <typename T> struct geometry_concept<polygon_set_data<T> > { typedef polygon_set_concept type; }; // template <typename T> // inline double compute_area(point_data<T>& a, point_data<T>& b, point_data<T>& c) { // return (double)(b.x()-a.x())*(double)(c.y()-a.y())- (double)(c.x()-a.x())*(double)(b.y()-a.y()); // } template <typename T> inline int make_resizing_vertex_list(std::vector<std::vector<point_data< T> > >& return_points, point_data<T>& curr_prev, bool ignore_prev_point, point_data< T> start, point_data<T> middle, point_data< T> end, double sizing_distance, unsigned int num_circle_segments, bool corner_fill_arc) { // handle the case of adding an intersection point point_data<double> dn1( middle.y()-start.y(), start.x()-middle.x()); double size = sizing_distance/std::sqrt( dn1.x()*dn1.x()+dn1.y()*dn1.y()); dn1 = point_data<double>( dn1.x()*size, dn1.y()* size); point_data<double> dn2( end.y()-middle.y(), middle.x()-end.x()); size = sizing_distance/std::sqrt( dn2.x()*dn2.x()+dn2.y()*dn2.y()); dn2 = point_data<double>( dn2.x()*size, dn2.y()* size); point_data<double> start_offset((start.x()+dn1.x()),(start.y()+dn1.y())); point_data<double> mid1_offset((middle.x()+dn1.x()),(middle.y()+dn1.y())); point_data<double> end_offset((end.x()+dn2.x()),(end.y()+dn2.y())); point_data<double> mid2_offset((middle.x()+dn2.x()),(middle.y()+dn2.y())); if (ignore_prev_point) curr_prev = round_down<T>(start_offset); if (corner_fill_arc) { std::vector<point_data< T> > return_points1; return_points.push_back(return_points1); std::vector<point_data< T> >& return_points_back = return_points[return_points.size()-1]; return_points_back.push_back(round_down<T>(mid1_offset)); return_points_back.push_back(middle); return_points_back.push_back(start); return_points_back.push_back(curr_prev); point_data<double> dmid(middle.x(),middle.y()); return_points.push_back(return_points1); int num = make_arc(return_points[return_points.size()-1],mid1_offset,mid2_offset,dmid,sizing_distance,num_circle_segments); curr_prev = round_down<T>(mid2_offset); return num; } std::pair<point_data<double>,point_data<double> > he1(start_offset,mid1_offset); std::pair<point_data<double>,point_data<double> > he2(mid2_offset ,end_offset); //typedef typename high_precision_type<double>::type high_precision; point_data<T> intersect; typename scanline_base<T>::compute_intersection_pack pack; bool res = pack.compute_intersection(intersect,he1,he2,true); if( res ) { std::vector<point_data< T> > return_points1; return_points.push_back(return_points1); std::vector<point_data< T> >& return_points_back = return_points[return_points.size()-1]; return_points_back.push_back(intersect); return_points_back.push_back(middle); return_points_back.push_back(start); return_points_back.push_back(curr_prev); //double d1= compute_area(intersect,middle,start); //double d2= compute_area(start,curr_prev,intersect); curr_prev = intersect; return return_points.size(); } return 0; } // this routine should take in start and end point s.t. end point is CCW from start // it sould make a pie slice polygon that is an intersection of that arc // with an ngon segments approximation of the circle centered at center with radius r // point start is gauaranteed to be on the segmentation // returnPoints will start with the first point after start // returnPoints vector may be empty template <typename T> inline int make_arc(std::vector<point_data< T> >& return_points, point_data< double> start, point_data< double> end, point_data< double> center, double r, unsigned int num_circle_segments) { const double our_pi=3.1415926535897932384626433832795028841971; // derive start and end angles double ps = atan2(start.y()-center.y(), start.x()-center.x()); double pe = atan2(end.y()-center.y(), end.x()-center.x()); if (ps < 0.0) ps += 2.0 * our_pi; if (pe <= 0.0) pe += 2.0 * our_pi; if (ps >= 2.0 * our_pi) ps -= 2.0 * our_pi; while (pe <= ps) pe += 2.0 * our_pi; double delta_angle = (2.0 * our_pi) / (double)num_circle_segments; if ( start==end) // full circle? { ps = delta_angle*0.5; pe = ps + our_pi * 2.0; double x,y; x = center.x() + r * cos(ps); y = center.y() + r * sin(ps); start = point_data<double>(x,y); end = start; } return_points.push_back(round_down<T>(center)); return_points.push_back(round_down<T>(start)); unsigned int i=0; double curr_angle = ps+delta_angle; while( curr_angle < pe - 0.01 && i < 2 * num_circle_segments) { i++; double x = center.x() + r * cos( curr_angle); double y = center.y() + r * sin( curr_angle); return_points.push_back( round_down<T>((point_data<double>(x,y)))); curr_angle+=delta_angle; } return_points.push_back(round_down<T>(end)); return return_points.size(); } }// close namespace }// close name space #include "detail/scan_arbitrary.hpp" namespace boost { namespace polygon { //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 <typename coordinate_type> class connectivity_extraction{ private: typedef arbitrary_connectivity_extraction<coordinate_type, int> ce; ce ce_; unsigned int nodeCount_; public: inline connectivity_extraction() : ce_(), nodeCount_(0) {} inline connectivity_extraction(const connectivity_extraction& that) : ce_(that.ce_), nodeCount_(that.nodeCount_) {} inline connectivity_extraction& operator=(const connectivity_extraction& that) { ce_ = that.ce_; 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_set_data<coordinate_type>& ps) { ps.clean(); ce_.populateTouchSetData(ps.begin(), ps.end(), nodeCount_); return nodeCount_++; } template <class GeoObjT> inline unsigned int insert(const GeoObjT& geoObj) { polygon_set_data<coordinate_type> 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 <class GraphT> inline void extract(GraphT& graph) { ce_.execute(graph); } }; template <typename T> polygon_set_data<T>& polygon_set_data<T>::interact(const polygon_set_data<T>& that) { connectivity_extraction<coordinate_type> ce; std::vector<polygon_with_holes_data<T> > polys; get(polys); clear(); for(std::size_t i = 0; i < polys.size(); ++i) { ce.insert(polys[i]); } int id = ce.insert(that); std::vector<std::set<int> > graph(id+1); ce.extract(graph); for(std::set<int>::iterator itr = graph[id].begin(); itr != graph[id].end(); ++itr) { insert(polys[*itr]); } return *this; } } } #include "polygon_set_traits.hpp" #include "detail/polygon_set_view.hpp" #include "polygon_set_concept.hpp" #include "detail/minkowski.hpp" #endif point_traits.hpp 0000644 00000002460 15125572616 0010010 0 ustar 00 // Boost.Polygon library point_traits.hpp header file // Copyright (c) Intel Corporation 2008. // Copyright (c) 2008-2012 Simonson Lucanus. // Copyright (c) 2012-2012 Andrii Sydorchuk. // See http://www.boost.org for updates, documentation, and revision history. // Use, modification and distribution is 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_POINT_TRAITS_HPP #define BOOST_POLYGON_POINT_TRAITS_HPP #include "isotropy.hpp" namespace boost { namespace polygon { template <typename PointType> struct point_traits { typedef PointType point_type; typedef typename point_type::coordinate_type coordinate_type; static coordinate_type get( const point_type& point, orientation_2d orient) { return point.get(orient); } }; template <typename PointType> struct point_mutable_traits { typedef PointType point_type; typedef typename point_type::coordinate_type coordinate_type; static void set( point_type& point, orientation_2d orient, coordinate_type value) { point.set(orient, value); } static point_type construct(coordinate_type x, coordinate_type y) { return point_type(x, y); } }; } // polygon } // boost #endif // BOOST_POLYGON_POINT_TRAITS_HPP interval_traits.hpp 0000644 00000002524 15125572616 0010504 0 ustar 00 // Boost.Polygon library interval_traits.hpp header file // Copyright (c) Intel Corporation 2008. // Copyright (c) 2008-2012 Simonson Lucanus. // Copyright (c) 2012-2012 Andrii Sydorchuk. // See http://www.boost.org for updates, documentation, and revision history. // Use, modification and distribution is 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_INTERVAL_TRAITS_HPP #define BOOST_POLYGON_INTERVAL_TRAITS_HPP #include "isotropy.hpp" namespace boost { namespace polygon { template <typename Interval> struct interval_traits { typedef Interval interval_type; typedef typename interval_type::coordinate_type coordinate_type; static coordinate_type get(const interval_type& interval, direction_1d dir) { return interval.get(dir); } }; template <typename Interval> struct interval_mutable_traits { typedef Interval interval_type; typedef typename interval_type::coordinate_type coordinate_type; static void set( interval_type& interval, direction_1d dir, coordinate_type value) { interval.set(dir, value); } static interval_type construct(coordinate_type low, coordinate_type high) { return interval_type(low, high); } }; } // polygon } // boost #endif // BOOST_POLICY_INTERVAL_TRAITS_HPP polygon.hpp 0000644 00000004562 15125572616 0006765 0 ustar 00 /* 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_HPP #define BOOST_POLYGON_POLYGON_HPP #define BOOST_POLYGON_VERSION 014401 #include "isotropy.hpp" //point #include "point_data.hpp" #include "point_traits.hpp" #include "point_concept.hpp" #include "transform.hpp" //interval #include "interval_data.hpp" #include "interval_traits.hpp" #include "interval_concept.hpp" //rectangle #include "rectangle_data.hpp" #include "rectangle_traits.hpp" #include "rectangle_concept.hpp" //segment #include "segment_data.hpp" #include "segment_traits.hpp" #include "segment_concept.hpp" //algorithms needed by polygon types #include "detail/iterator_points_to_compact.hpp" #include "detail/iterator_compact_to_points.hpp" //polygons #include "polygon_45_data.hpp" #include "polygon_data.hpp" #include "polygon_90_data.hpp" #include "polygon_90_with_holes_data.hpp" #include "polygon_45_with_holes_data.hpp" #include "polygon_with_holes_data.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" //45 boolean op algorithms #include "detail/boolean_op_45.hpp" #include "detail/polygon_45_formation.hpp" //polygon set data types #include "polygon_90_set_data.hpp" //polygon set trait types #include "polygon_90_set_traits.hpp" //polygon set concepts #include "polygon_90_set_concept.hpp" //boolean operator syntax #include "detail/polygon_90_set_view.hpp" //45 boolean op algorithms #include "detail/polygon_45_touch.hpp" #include "detail/property_merge_45.hpp" #include "polygon_45_set_data.hpp" #include "polygon_45_set_traits.hpp" #include "polygon_45_set_concept.hpp" #include "detail/polygon_45_set_view.hpp" //arbitrary polygon algorithms #include "detail/polygon_arbitrary_formation.hpp" #include "polygon_set_data.hpp" //general scanline #include "detail/scan_arbitrary.hpp" #include "polygon_set_traits.hpp" #include "detail/polygon_set_view.hpp" #include "polygon_set_concept.hpp" #include "segment_utils.hpp" #endif polygon_45_with_holes_data.hpp 0000644 00000006666 15125572616 0012522 0 ustar 00 /* 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_45_WITH_HOLES_DATA_HPP #define BOOST_POLYGON_POLYGON_45_WITH_HOLES_DATA_HPP #include "isotropy.hpp" #include "polygon_45_data.hpp" namespace boost { namespace polygon{ struct polygon_45_with_holes_concept; template <typename T> class polygon_45_with_holes_data { public: typedef polygon_45_with_holes_concept geometry_type; typedef T coordinate_type; typedef typename polygon_45_data<T>::iterator_type iterator_type; typedef typename std::list<polygon_45_data<coordinate_type> >::const_iterator iterator_holes_type; typedef polygon_45_data<coordinate_type> hole_type; typedef typename coordinate_traits<T>::coordinate_distance area_type; typedef point_data<T> point_type; // default constructor of point does not initialize x and y inline polygon_45_with_holes_data() : self_(), holes_() {} //do nothing default constructor template<class iT> inline polygon_45_with_holes_data(iT input_begin, iT input_end) : self_(), holes_() { set(input_begin, input_end); } template<class iT, typename hiT> inline polygon_45_with_holes_data(iT input_begin, iT input_end, hiT holes_begin, hiT holes_end) : self_(), holes_() { set(input_begin, input_end); set_holes(holes_begin, holes_end); } template<class iT> inline polygon_45_with_holes_data& set(iT input_begin, iT input_end) { self_.set(input_begin, input_end); return *this; } // initialize a polygon from x,y values, it is assumed that the first is an x // and that the input is a well behaved polygon template<class iT> inline polygon_45_with_holes_data& set_holes(iT input_begin, iT input_end) { holes_.clear(); //just in case there was some old data there for( ; input_begin != input_end; ++ input_begin) { holes_.push_back(hole_type()); holes_.back().set((*input_begin).begin(), (*input_begin).end()); } return *this; } // copy constructor (since we have dynamic memory) inline polygon_45_with_holes_data(const polygon_45_with_holes_data& that) : self_(that.self_), holes_(that.holes_) {} // assignment operator (since we have dynamic memory do a deep copy) inline polygon_45_with_holes_data& operator=(const polygon_45_with_holes_data& that) { self_ = that.self_; holes_ = that.holes_; return *this; } template <typename T2> inline polygon_45_with_holes_data& operator=(const T2& rvalue); // get begin iterator, returns a pointer to a const coordinate_type inline const iterator_type begin() const { return self_.begin(); } // get end iterator, returns a pointer to a const coordinate_type inline const iterator_type end() const { return self_.end(); } inline std::size_t size() const { return self_.size(); } // get begin iterator, returns a pointer to a const polygon inline const iterator_holes_type begin_holes() const { return holes_.begin(); } // get end iterator, returns a pointer to a const polygon inline const iterator_holes_type end_holes() const { return holes_.end(); } inline std::size_t size_holes() const { return holes_.size(); } public: polygon_45_data<coordinate_type> self_; std::list<hole_type> holes_; }; } } #endif voronoi.hpp 0000644 00000010637 15125572616 0006771 0 ustar 00 // Boost.Polygon library voronoi.hpp header file // Copyright Andrii Sydorchuk 2010-2012. // Distributed under 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) // See http://www.boost.org for updates, documentation, and revision history. #ifndef BOOST_POLYGON_VORONOI #define BOOST_POLYGON_VORONOI #include "isotropy.hpp" #include "point_concept.hpp" #include "segment_concept.hpp" #include "voronoi_builder.hpp" #include "voronoi_diagram.hpp" // Public methods to compute Voronoi diagram of a set of points and segments. // Coordinates of the points and of the endpoints of the segments should belong // to the 32-bit signed integer range [-2^31, 2^31-1]. To use wider input // coordinate range voronoi_builder configuration via coordinate type traits // is required. // Complexity - O(N*logN), memory usage - O(N), N - number of input objects. namespace boost { namespace polygon { template <typename Point, typename VB> typename enable_if< typename gtl_if< typename is_point_concept< typename geometry_concept<Point>::type >::type >::type, std::size_t >::type insert(const Point& point, VB* vb) { return vb->insert_point(x(point), y(point)); } template <typename PointIterator, typename VB> typename enable_if< typename gtl_if< typename is_point_concept< typename geometry_concept< typename std::iterator_traits<PointIterator>::value_type >::type >::type >::type, void >::type insert(const PointIterator first, const PointIterator last, VB* vb) { for (PointIterator it = first; it != last; ++it) { insert(*it, vb); } } template <typename Segment, typename VB> typename enable_if< typename gtl_if< typename is_segment_concept< typename geometry_concept<Segment>::type >::type >::type, std::size_t >::type insert(const Segment& segment, VB* vb) { return vb->insert_segment( x(low(segment)), y(low(segment)), x(high(segment)), y(high(segment))); } template <typename SegmentIterator, typename VB> typename enable_if< typename gtl_if< typename is_segment_concept< typename geometry_concept< typename std::iterator_traits<SegmentIterator>::value_type >::type >::type >::type, void >::type insert(const SegmentIterator first, const SegmentIterator last, VB* vb) { for (SegmentIterator it = first; it != last; ++it) { insert(*it, vb); } } template <typename PointIterator, typename VD> typename enable_if< typename gtl_if< typename is_point_concept< typename geometry_concept< typename std::iterator_traits<PointIterator>::value_type >::type >::type >::type, void >::type construct_voronoi(const PointIterator first, const PointIterator last, VD* vd) { default_voronoi_builder builder; insert(first, last, &builder); builder.construct(vd); } template <typename SegmentIterator, typename VD> typename enable_if< typename gtl_if< typename is_segment_concept< typename geometry_concept< typename std::iterator_traits<SegmentIterator>::value_type >::type >::type >::type, void >::type construct_voronoi(const SegmentIterator first, const SegmentIterator last, VD* vd) { default_voronoi_builder builder; insert(first, last, &builder); builder.construct(vd); } template <typename PointIterator, typename SegmentIterator, typename VD> typename enable_if< typename gtl_and< typename gtl_if< typename is_point_concept< typename geometry_concept< typename std::iterator_traits<PointIterator>::value_type >::type >::type >::type, typename gtl_if< typename is_segment_concept< typename geometry_concept< typename std::iterator_traits<SegmentIterator>::value_type >::type >::type >::type >::type, void >::type construct_voronoi(const PointIterator p_first, const PointIterator p_last, const SegmentIterator s_first, const SegmentIterator s_last, VD* vd) { default_voronoi_builder builder; insert(p_first, p_last, &builder); insert(s_first, s_last, &builder); builder.construct(vd); } } // polygon } // boost #endif // BOOST_POLYGON_VORONOI voronoi_geometry_type.hpp 0000644 00000002577 15125572616 0011751 0 ustar 00 // Boost.Polygon library voronoi_geometry_type.hpp header file // Copyright Andrii Sydorchuk 2010-2012. // Distributed under 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) // See http://www.boost.org for updates, documentation, and revision history. #ifndef BOOST_POLYGON_VORONOI_GEOMETRY_TYPE #define BOOST_POLYGON_VORONOI_GEOMETRY_TYPE #include <cstddef> namespace boost { namespace polygon { // Represents topology type of the voronoi site. enum GeometryCategory { GEOMETRY_CATEGORY_POINT = 0x0, GEOMETRY_CATEGORY_SEGMENT = 0x1 }; // Represents category of the input source that forms Voronoi cell. enum SourceCategory { // Point subtypes. SOURCE_CATEGORY_SINGLE_POINT = 0x0, SOURCE_CATEGORY_SEGMENT_START_POINT = 0x1, SOURCE_CATEGORY_SEGMENT_END_POINT = 0x2, // Segment subtypes. SOURCE_CATEGORY_INITIAL_SEGMENT = 0x8, SOURCE_CATEGORY_REVERSE_SEGMENT = 0x9, SOURCE_CATEGORY_GEOMETRY_SHIFT = 0x3, SOURCE_CATEGORY_BITMASK = 0x1F }; inline bool belongs( SourceCategory source_category, GeometryCategory geometry_category) { return (static_cast<std::size_t>(source_category) >> SOURCE_CATEGORY_GEOMETRY_SHIFT) == static_cast<std::size_t>(geometry_category); } } // polygon } // boost #endif // BOOST_POLYGON_VORONOI_GEOMETRY_TYPE polygon_set_traits.hpp 0000644 00000012411 15125572616 0011216 0 ustar 00 /* 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_SET_TRAITS_HPP #define BOOST_POLYGON_POLYGON_SET_TRAITS_HPP namespace boost { namespace polygon{ struct polygon_set_concept {}; //default definition of polygon set traits works for any model of polygon , polygon with holes or any vector or list thereof template <typename T> struct polygon_set_traits { typedef typename get_coordinate_type<T, typename geometry_concept<T>::type >::type coordinate_type; typedef typename get_iterator_type<T>::type iterator_type; typedef T operator_arg_type; static inline iterator_type begin(const T& polygon_set) { return get_iterator_type<T>::begin(polygon_set); } static inline iterator_type end(const T& polygon_set) { return get_iterator_type<T>::end(polygon_set); } static inline bool clean(const T& ) { return false; } static inline bool sorted(const T& ) { return false; } }; template <typename T> struct is_polygonal_concept { typedef gtl_no type; }; template <> struct is_polygonal_concept<polygon_concept> { typedef gtl_yes type; }; template <> struct is_polygonal_concept<polygon_with_holes_concept> { typedef gtl_yes type; }; template <> struct is_polygonal_concept<polygon_set_concept> { typedef gtl_yes type; }; template <typename T> struct is_polygon_set_type { typedef typename is_polygonal_concept<typename geometry_concept<T>::type>::type type; }; template <typename T> struct is_polygon_set_type<std::list<T> > { typedef typename gtl_or< typename is_polygonal_concept<typename geometry_concept<std::list<T> >::type>::type, typename is_polygonal_concept<typename geometry_concept<typename std::list<T>::value_type>::type>::type>::type type; }; template <typename T> struct is_polygon_set_type<std::vector<T> > { typedef typename gtl_or< typename is_polygonal_concept<typename geometry_concept<std::vector<T> >::type>::type, typename is_polygonal_concept<typename geometry_concept<typename std::vector<T>::value_type>::type>::type>::type type; }; template <typename T> struct is_mutable_polygon_set_type { typedef typename gtl_same_type<polygon_set_concept, typename geometry_concept<T>::type>::type type; }; template <typename T> struct is_mutable_polygon_set_type<std::list<T> > { typedef typename gtl_or< typename gtl_same_type<polygon_set_concept, typename geometry_concept<std::list<T> >::type>::type, typename is_polygonal_concept<typename geometry_concept<typename std::list<T>::value_type>::type>::type>::type type; }; template <typename T> struct is_mutable_polygon_set_type<std::vector<T> > { typedef typename gtl_or< typename gtl_same_type<polygon_set_concept, typename geometry_concept<std::vector<T> >::type>::type, typename is_polygonal_concept<typename geometry_concept<typename std::vector<T>::value_type>::type>::type>::type type; }; template <typename T> struct polygon_set_mutable_traits {}; template <typename T> struct polygon_set_mutable_traits<std::list<T> > { template <typename input_iterator_type> static inline void set(std::list<T>& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { polygon_set.clear(); polygon_set_data<typename polygon_set_traits<std::list<T> >::coordinate_type> ps; ps.reserve(std::distance(input_begin, input_end)); ps.insert(input_begin, input_end); ps.get(polygon_set); } }; template <typename T> struct polygon_set_mutable_traits<std::vector<T> > { template <typename input_iterator_type> static inline void set(std::vector<T>& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { polygon_set.clear(); size_t num_ele = std::distance(input_begin, input_end); polygon_set.reserve(num_ele); polygon_set_data<typename polygon_set_traits<std::list<T> >::coordinate_type> ps; ps.reserve(num_ele); ps.insert(input_begin, input_end); ps.get(polygon_set); } }; template <typename T> struct polygon_set_mutable_traits<polygon_set_data<T> > { template <typename input_iterator_type> static inline void set(polygon_set_data<T>& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { polygon_set.set(input_begin, input_end); } }; template <typename T> struct polygon_set_traits<polygon_set_data<T> > { typedef typename polygon_set_data<T>::coordinate_type coordinate_type; typedef typename polygon_set_data<T>::iterator_type iterator_type; typedef typename polygon_set_data<T>::operator_arg_type operator_arg_type; static inline iterator_type begin(const polygon_set_data<T>& polygon_set) { return polygon_set.begin(); } static inline iterator_type end(const polygon_set_data<T>& polygon_set) { return polygon_set.end(); } static inline bool clean(const polygon_set_data<T>& polygon_set) { polygon_set.clean(); return true; } static inline bool sorted(const polygon_set_data<T>& polygon_set) { polygon_set.sort(); return true; } }; } } #endif polygon_45_data.hpp 0000644 00000004432 15125572616 0010262 0 ustar 00 /* 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_45_DATA_HPP #define BOOST_POLYGON_POLYGON_45_DATA_HPP #include "isotropy.hpp" namespace boost { namespace polygon{ struct polygon_45_concept; template <typename T> class polygon_data; template <typename T> class polygon_45_data { public: typedef polygon_45_concept geometry_type; typedef T coordinate_type; typedef typename std::vector<point_data<coordinate_type> >::const_iterator iterator_type; typedef typename coordinate_traits<T>::coordinate_distance area_type; typedef point_data<T> point_type; inline polygon_45_data() : coords_() {} //do nothing default constructor template<class iT> inline polygon_45_data(iT input_begin, iT input_end) : coords_(input_begin, input_end) {} template<class iT> inline polygon_45_data& set(iT input_begin, iT input_end) { coords_.clear(); //just in case there was some old data there coords_.insert(coords_.end(), input_begin, input_end); return *this; } // copy constructor (since we have dynamic memory) inline polygon_45_data(const polygon_45_data& that) : coords_(that.coords_) {} // assignment operator (since we have dynamic memory do a deep copy) inline polygon_45_data& operator=(const polygon_45_data& that) { coords_ = that.coords_; return *this; } template <typename T2> inline polygon_45_data& operator=(const T2& rvalue); inline bool operator==(const polygon_45_data& that) const { if(coords_.size() != that.coords_.size()) return false; for(std::size_t i = 0; i < coords_.size(); ++i) { if(coords_[i] != that.coords_[i]) return false; } return true; } inline bool operator!=(const polygon_45_data& that) const { return !((*this) == that); } // get begin iterator, returns a pointer to a const Unit inline iterator_type begin() const { return coords_.begin(); } // get end iterator, returns a pointer to a const Unit inline iterator_type end() const { return coords_.end(); } inline std::size_t size() const { return coords_.size(); } public: std::vector<point_data<coordinate_type> > coords_; }; } } #endif point_concept.hpp 0000644 00000030707 15125572616 0010142 0 ustar 00 // Boost.Polygon library point_concept.hpp header file // Copyright (c) Intel Corporation 2008. // Copyright (c) 2008-2012 Simonson Lucanus. // Copyright (c) 2012-2012 Andrii Sydorchuk. // See http://www.boost.org for updates, documentation, and revision history. // Use, modification and distribution is 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_POINT_CONCEPT_HPP #define BOOST_POLYGON_POINT_CONCEPT_HPP #include "isotropy.hpp" #include "point_traits.hpp" namespace boost { namespace polygon { struct point_concept {}; template <typename ConceptType> struct is_point_concept { typedef gtl_no type; }; template <> struct is_point_concept<point_concept> { typedef gtl_yes type; }; template <typename ConceptType> struct is_mutable_point_concept { typedef gtl_no type; }; template <> struct is_mutable_point_concept<point_concept> { typedef gtl_yes type; }; template <typename GeometryType, typename BoolType> struct point_coordinate_type_by_concept { typedef void type; }; template <typename GeometryType> struct point_coordinate_type_by_concept<GeometryType, gtl_yes> { typedef typename point_traits<GeometryType>::coordinate_type type; }; template <typename GeometryType> struct point_coordinate_type { typedef typename point_coordinate_type_by_concept< GeometryType, typename is_point_concept< typename geometry_concept<GeometryType>::type >::type >::type type; }; template <typename GeometryType, typename BoolType> struct point_difference_type_by_concept { typedef void type; }; template <typename GeometryType> struct point_difference_type_by_concept<GeometryType, gtl_yes> { typedef typename coordinate_traits< typename point_traits<GeometryType>::coordinate_type >::coordinate_difference type; }; template <typename GeometryType> struct point_difference_type { typedef typename point_difference_type_by_concept< GeometryType, typename is_point_concept< typename geometry_concept<GeometryType>::type >::type >::type type; }; template <typename GeometryType, typename BoolType> struct point_distance_type_by_concept { typedef void type; }; template <typename GeometryType> struct point_distance_type_by_concept<GeometryType, gtl_yes> { typedef typename coordinate_traits< typename point_coordinate_type<GeometryType>::type >::coordinate_distance type; }; template <typename GeometryType> struct point_distance_type { typedef typename point_distance_type_by_concept< GeometryType, typename is_point_concept< typename geometry_concept<GeometryType>::type >::type >::type type; }; struct y_pt_get : gtl_yes {}; template <typename PointType> typename enable_if< typename gtl_and< y_pt_get, typename is_point_concept< typename geometry_concept<PointType>::type >::type >::type, typename point_coordinate_type<PointType>::type >::type get(const PointType& point, orientation_2d orient) { return point_traits<PointType>::get(point, orient); } struct y_pt_set : gtl_yes {}; template <typename PointType> typename enable_if< typename gtl_and< y_pt_set, typename is_mutable_point_concept< typename geometry_concept<PointType>::type >::type >::type, void >::type set(PointType& point, orientation_2d orient, typename point_mutable_traits<PointType>::coordinate_type value) { point_mutable_traits<PointType>::set(point, orient, value); } struct y_pt_construct : gtl_yes {}; template <typename PointType> typename enable_if< typename gtl_and< y_pt_construct, typename is_mutable_point_concept< typename geometry_concept<PointType>::type >::type >::type, PointType>::type construct( typename point_mutable_traits<PointType>::coordinate_type x, typename point_mutable_traits<PointType>::coordinate_type y) { return point_mutable_traits<PointType>::construct(x, y); } struct y_pt_assign : gtl_yes {}; template <typename PointType1, typename PointType2> typename enable_if< typename gtl_and_3< y_pt_assign, typename is_mutable_point_concept< typename geometry_concept<PointType1>::type >::type, typename is_point_concept< typename geometry_concept<PointType2>::type >::type >::type, PointType1>::type& assign(PointType1& lvalue, const PointType2& rvalue) { set(lvalue, HORIZONTAL, get(rvalue, HORIZONTAL)); set(lvalue, VERTICAL, get(rvalue, VERTICAL)); return lvalue; } struct y_p_x : gtl_yes {}; template <typename PointType> typename enable_if< typename gtl_and< y_p_x, typename is_point_concept< typename geometry_concept<PointType>::type >::type >::type, typename point_coordinate_type<PointType>::type >::type x(const PointType& point) { return get(point, HORIZONTAL); } struct y_p_y : gtl_yes {}; template <typename PointType> typename enable_if< typename gtl_and< y_p_y, typename is_point_concept< typename geometry_concept<PointType>::type >::type >::type, typename point_coordinate_type<PointType>::type >::type y(const PointType& point) { return get(point, VERTICAL); } struct y_p_sx : gtl_yes {}; template <typename PointType> typename enable_if< typename gtl_and< y_p_sx, typename is_mutable_point_concept< typename geometry_concept<PointType>::type >::type >::type, void>::type x(PointType& point, typename point_mutable_traits<PointType>::coordinate_type value) { set(point, HORIZONTAL, value); } struct y_p_sy : gtl_yes {}; template <typename PointType> typename enable_if< typename gtl_and< y_p_sy, typename is_mutable_point_concept< typename geometry_concept<PointType>::type >::type >::type, void>::type y(PointType& point, typename point_mutable_traits<PointType>::coordinate_type value) { set(point, VERTICAL, value); } struct y_pt_equiv : gtl_yes {}; template <typename PointType1, typename PointType2> typename enable_if< typename gtl_and_3< y_pt_equiv, typename is_point_concept< typename geometry_concept<PointType1>::type >::type, typename is_point_concept< typename geometry_concept<PointType2>::type >::type >::type, bool>::type equivalence( const PointType1& point1, const PointType2& point2) { return (x(point1) == x(point2)) && (y(point1) == y(point2)); } struct y_pt_man_dist : gtl_yes {}; template <typename PointType1, typename PointType2> typename enable_if< typename gtl_and_3< y_pt_man_dist, typename is_point_concept< typename geometry_concept<PointType1>::type >::type, typename is_point_concept< typename geometry_concept<PointType2>::type >::type >::type, typename point_difference_type<PointType1>::type>::type manhattan_distance(const PointType1& point1, const PointType2& point2) { return euclidean_distance(point1, point2, HORIZONTAL) + euclidean_distance(point1, point2, VERTICAL); } struct y_pt_ed1 : gtl_yes {}; template <typename PointType1, typename PointType2> typename enable_if< typename gtl_and_3< y_pt_ed1, typename is_point_concept< typename geometry_concept<PointType1>::type >::type, typename is_point_concept< typename geometry_concept<PointType2>::type >::type >::type, typename point_difference_type<PointType1>::type>::type euclidean_distance( const PointType1& point1, const PointType2& point2, orientation_2d orient) { typename point_difference_type<PointType1>::type dif = get(point1, orient) - get(point2, orient); return (dif < 0) ? -dif : dif; } struct y_pt_eds : gtl_yes {}; template <typename PointType1, typename PointType2> typename enable_if< typename gtl_and_3< y_pt_eds, typename is_point_concept< typename geometry_concept<PointType1>::type >::type, typename is_point_concept< typename geometry_concept<PointType2>::type >::type >::type, typename point_difference_type<PointType1>::type>::type distance_squared(const PointType1& point1, const PointType2& point2) { typename point_difference_type<PointType1>::type dx = euclidean_distance(point1, point2, HORIZONTAL); typename point_difference_type<PointType1>::type dy = euclidean_distance(point1, point2, VERTICAL); dx *= dx; dy *= dy; return dx + dy; } struct y_pt_ed2 : gtl_yes {}; template <typename PointType1, typename PointType2> typename enable_if< typename gtl_and_3< y_pt_ed2, typename is_point_concept< typename geometry_concept<PointType1>::type >::type, typename is_point_concept< typename geometry_concept<PointType2>::type >::type >::type, typename point_distance_type<PointType1>::type>::type euclidean_distance(const PointType1& point1, const PointType2& point2) { return (std::sqrt)( static_cast<double>(distance_squared(point1, point2))); } struct y_pt_convolve : gtl_yes {}; template <typename PointType1, typename PointType2> typename enable_if< typename gtl_and_3< y_pt_convolve, typename is_mutable_point_concept< typename geometry_concept<PointType1>::type >::type, typename is_point_concept< typename geometry_concept<PointType2>::type >::type >::type, PointType1>::type& convolve(PointType1& lvalue, const PointType2& rvalue) { x(lvalue, x(lvalue) + x(rvalue)); y(lvalue, y(lvalue) + y(rvalue)); return lvalue; } struct y_pt_deconvolve : gtl_yes {}; template <typename PointType1, typename PointType2> typename enable_if< typename gtl_and_3< y_pt_deconvolve, typename is_mutable_point_concept< typename geometry_concept<PointType1>::type >::type, typename is_point_concept< typename geometry_concept<PointType2>::type >::type >::type, PointType1>::type& deconvolve(PointType1& lvalue, const PointType2& rvalue) { x(lvalue, x(lvalue) - x(rvalue)); y(lvalue, y(lvalue) - y(rvalue)); return lvalue; } struct y_pt_scale_up : gtl_yes {}; template <typename PointType, typename CType> typename enable_if< typename gtl_and< y_pt_scale_up, typename is_mutable_point_concept< typename geometry_concept<PointType>::type >::type >::type, PointType>::type& scale_up(PointType& point, CType factor) { typedef typename point_coordinate_type<PointType>::type Unit; x(point, x(point) * (Unit)factor); y(point, y(point) * (Unit)factor); return point; } struct y_pt_scale_down : gtl_yes {}; template <typename PointType, typename CType> typename enable_if< typename gtl_and< y_pt_scale_down, typename is_mutable_point_concept< typename geometry_concept<PointType>::type >::type >::type, PointType>::type& scale_down(PointType& point, CType factor) { typedef typename point_coordinate_type<PointType>::type Unit; typedef typename coordinate_traits<Unit>::coordinate_distance dt; x(point, scaling_policy<Unit>::round((dt)(x(point)) / (dt)factor)); y(point, scaling_policy<Unit>::round((dt)(y(point)) / (dt)factor)); return point; } struct y_pt_scale : gtl_yes {}; template <typename PointType, typename ScaleType> typename enable_if< typename gtl_and< y_pt_scale, typename is_mutable_point_concept< typename geometry_concept<PointType>::type >::type >::type, PointType>::type& scale(PointType& point, const ScaleType& scaling) { typedef typename point_coordinate_type<PointType>::type Unit; Unit x_coord(x(point)); Unit y_coord(y(point)); scaling.scale(x_coord, y_coord); x(point, x_coord); y(point, y_coord); return point; } struct y_pt_transform : gtl_yes {}; template <typename PointType, typename TransformType> typename enable_if< typename gtl_and< y_pt_transform, typename is_mutable_point_concept< typename geometry_concept<PointType>::type >::type >::type, PointType>::type& transform(PointType& point, const TransformType& transform) { typedef typename point_coordinate_type<PointType>::type Unit; Unit x_coord(x(point)); Unit y_coord(y(point)); transform.transform(x_coord, y_coord); x(point, x_coord); y(point, y_coord); return point; } struct y_pt_move : gtl_yes {}; template <typename PointType> typename enable_if< typename gtl_and< y_pt_move, typename is_mutable_point_concept< typename geometry_concept<PointType>::type >::type >::type, PointType>::type& move(PointType& point, orientation_2d orient, typename point_coordinate_type<PointType>::type displacement) { typedef typename point_coordinate_type<PointType>::type Unit; Unit coord = get(point, orient); set(point, orient, coord + displacement); return point; } } // polygon } // boost #endif // BOOST_POLYGON_POINT_CONCEPT_HPP rectangle_traits.hpp 0000644 00000002505 15125572616 0010623 0 ustar 00 /* 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_RECTANGLE_TRAITS_HPP #define BOOST_POLYGON_RECTANGLE_TRAITS_HPP #include "isotropy.hpp" namespace boost { namespace polygon{ template <typename T, typename enable = gtl_yes> struct rectangle_traits {}; template <typename T> struct rectangle_traits<T, gtl_no> {}; template <typename T> struct rectangle_traits<T, typename gtl_same_type<typename T::interval_type, typename T::interval_type>::type> { typedef typename T::coordinate_type coordinate_type; typedef typename T::interval_type interval_type; static inline interval_type get(const T& rectangle, orientation_2d orient) { return rectangle.get(orient); } }; template <typename T> struct rectangle_mutable_traits { template <typename T2> static inline void set(T& rectangle, orientation_2d orient, const T2& interval) { rectangle.set(orient, interval); } template <typename T2, typename T3> static inline T construct(const T2& interval_horizontal, const T3& interval_vertical) { return T(interval_horizontal, interval_vertical); } }; } } #endif segment_traits.hpp 0000644 00000002667 15125572616 0010332 0 ustar 00 // Boost.Polygon library segment_traits.hpp header file // Copyright (c) Intel Corporation 2008. // Copyright (c) 2008-2012 Simonson Lucanus. // Copyright (c) 2012-2012 Andrii Sydorchuk. // See http://www.boost.org for updates, documentation, and revision history. // Use, modification and distribution is 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_SEGMENT_TRAITS_HPP #define BOOST_POLYGON_SEGMENT_TRAITS_HPP #include "isotropy.hpp" namespace boost { namespace polygon { template <typename Segment> struct segment_traits { typedef Segment segment_type; typedef typename segment_type::point_type point_type; typedef typename segment_type::coordinate_type coordinate_type; static point_type get( const segment_type& segment, direction_1d dir) { return segment.get(dir); } }; template <typename Segment> struct segment_mutable_traits { typedef Segment segment_type; typedef typename segment_type::point_type point_type; typedef typename segment_type::coordinate_type coordinate_type; static void set( segment_type& segment, direction_1d dir, const point_type& point) { segment.set(dir, point); } static segment_type construct(const point_type& low, const point_type& high) { return segment_type(low, high); } }; } // polygon } // boost #endif // BOOST_POLYGON_SEGMENT_TRAITS_HPP isotropy.hpp 0000644 00000042243 15125572616 0007164 0 ustar 00 /* 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_ISOTROPY_HPP #define BOOST_POLYGON_ISOTROPY_HPP //external #include <cmath> #include <cstddef> #include <cstdlib> #include <vector> #include <deque> #include <map> #include <set> #include <list> //#include <iostream> #include <algorithm> #include <limits> #include <iterator> #include <string> #ifndef BOOST_POLYGON_NO_DEPS #include <boost/config.hpp> #ifdef BOOST_MSVC #define BOOST_POLYGON_MSVC #endif #ifdef BOOST_INTEL #define BOOST_POLYGON_ICC #endif #ifdef BOOST_HAS_LONG_LONG #define BOOST_POLYGON_USE_LONG_LONG typedef boost::long_long_type polygon_long_long_type; typedef boost::ulong_long_type polygon_ulong_long_type; //typedef long long polygon_long_long_type; //typedef unsigned long long polygon_ulong_long_type; #endif #else #ifdef _WIN32 #define BOOST_POLYGON_MSVC #endif #ifdef __ICC #define BOOST_POLYGON_ICC #endif #define BOOST_POLYGON_USE_LONG_LONG typedef long long polygon_long_long_type; typedef unsigned long long polygon_ulong_long_type; #endif namespace boost { namespace polygon{ enum GEOMETRY_CONCEPT_ID { COORDINATE_CONCEPT, INTERVAL_CONCEPT, POINT_CONCEPT, POINT_3D_CONCEPT, RECTANGLE_CONCEPT, POLYGON_90_CONCEPT, POLYGON_90_WITH_HOLES_CONCEPT, POLYGON_45_CONCEPT, POLYGON_45_WITH_HOLES_CONCEPT, POLYGON_CONCEPT, POLYGON_WITH_HOLES_CONCEPT, POLYGON_90_SET_CONCEPT, POLYGON_45_SET_CONCEPT, POLYGON_SET_CONCEPT }; struct undefined_concept {}; template <typename T> struct geometry_concept { typedef undefined_concept type; }; template <typename GCT, typename T> struct view_of {}; template <typename T1, typename T2> view_of<T1, T2> view_as(const T2& obj) { return view_of<T1, T2>(obj); } template <typename T, bool /*enable*/ = true> struct coordinate_traits {}; //used to override long double with an infinite precision datatype template <typename T> struct high_precision_type { typedef long double type; }; template <typename T> T convert_high_precision_type(const typename high_precision_type<T>::type& v) { return T(v); } //used to override std::sort with an alternative (parallel) algorithm template <typename iter_type> void polygon_sort(iter_type _b_, iter_type _e_); template <typename iter_type, typename pred_type> void polygon_sort(iter_type _b_, iter_type _e_, const pred_type& _pred_); template <> struct coordinate_traits<int> { typedef int coordinate_type; typedef long double area_type; #ifdef BOOST_POLYGON_USE_LONG_LONG typedef polygon_long_long_type manhattan_area_type; typedef polygon_ulong_long_type unsigned_area_type; typedef polygon_long_long_type coordinate_difference; #else typedef long manhattan_area_type; typedef unsigned long unsigned_area_type; typedef long coordinate_difference; #endif typedef long double coordinate_distance; }; template<> struct coordinate_traits<long, sizeof(long) == sizeof(int)> { typedef coordinate_traits<int> cT_; typedef cT_::coordinate_type coordinate_type; typedef cT_::area_type area_type; typedef cT_::manhattan_area_type manhattan_area_type; typedef cT_::unsigned_area_type unsigned_area_type; typedef cT_::coordinate_difference coordinate_difference; typedef cT_::coordinate_distance coordinate_distance; }; #ifdef BOOST_POLYGON_USE_LONG_LONG template <> struct coordinate_traits<polygon_long_long_type> { typedef polygon_long_long_type coordinate_type; typedef long double area_type; typedef polygon_long_long_type manhattan_area_type; typedef polygon_ulong_long_type unsigned_area_type; typedef polygon_long_long_type coordinate_difference; typedef long double coordinate_distance; }; template<> struct coordinate_traits<long, sizeof(long) == sizeof(polygon_long_long_type)> { typedef coordinate_traits<polygon_long_long_type> cT_; typedef cT_::coordinate_type coordinate_type; typedef cT_::area_type area_type; typedef cT_::manhattan_area_type manhattan_area_type; typedef cT_::unsigned_area_type unsigned_area_type; typedef cT_::coordinate_difference coordinate_difference; typedef cT_::coordinate_distance coordinate_distance; }; #endif template <> struct coordinate_traits<float> { typedef float coordinate_type; typedef float area_type; typedef float manhattan_area_type; typedef float unsigned_area_type; typedef float coordinate_difference; typedef float coordinate_distance; }; template <> struct coordinate_traits<double> { typedef double coordinate_type; typedef double area_type; typedef double manhattan_area_type; typedef double unsigned_area_type; typedef double coordinate_difference; typedef double coordinate_distance; }; template <> struct coordinate_traits<long double> { typedef long double coordinate_type; typedef long double area_type; typedef long double manhattan_area_type; typedef long double unsigned_area_type; typedef long double coordinate_difference; typedef long double coordinate_distance; }; template <typename T> struct scaling_policy { template <typename T2> static inline T round(T2 t2) { return (T)std::floor(t2+0.5); } static inline T round(T t2) { return t2; } }; struct coordinate_concept {}; template <> struct geometry_concept<int> { typedef coordinate_concept type; }; #ifdef BOOST_POLYGON_USE_LONG_LONG template <> struct geometry_concept<polygon_long_long_type> { typedef coordinate_concept type; }; #endif template <> struct geometry_concept<float> { typedef coordinate_concept type; }; template <> struct geometry_concept<double> { typedef coordinate_concept type; }; template <> struct geometry_concept<long double> { typedef coordinate_concept type; }; struct gtl_no { static const bool value = false; }; struct gtl_yes { typedef gtl_yes type; static const bool value = true; }; template <bool T, bool T2> struct gtl_and_c { typedef gtl_no type; }; template <> struct gtl_and_c<true, true> { typedef gtl_yes type; }; template <typename T, typename T2> struct gtl_and : gtl_and_c<T::value, T2::value> {}; template <typename T, typename T2, typename T3> struct gtl_and_3 { typedef typename gtl_and< T, typename gtl_and<T2, T3>::type>::type type; }; template <typename T, typename T2, typename T3, typename T4> struct gtl_and_4 { typedef typename gtl_and_3< T, T2, typename gtl_and<T3, T4>::type>::type type; }; template <typename T, typename T2> struct gtl_or { typedef gtl_yes type; }; template <typename T> struct gtl_or<T, T> { typedef T type; }; template <typename T, typename T2, typename T3> struct gtl_or_3 { typedef typename gtl_or< T, typename gtl_or<T2, T3>::type>::type type; }; template <typename T, typename T2, typename T3, typename T4> struct gtl_or_4 { typedef typename gtl_or< T, typename gtl_or_3<T2, T3, T4>::type>::type type; }; template <typename T> struct gtl_not { typedef gtl_no type; }; template <> struct gtl_not<gtl_no> { typedef gtl_yes type; }; template <typename T> struct gtl_if { #ifdef BOOST_POLYGON_MSVC typedef gtl_no type; #endif }; template <> struct gtl_if<gtl_yes> { typedef gtl_yes type; }; template <typename T, typename T2> struct gtl_same_type { typedef gtl_no type; }; template <typename T> struct gtl_same_type<T, T> { typedef gtl_yes type; }; template <typename T, typename T2> struct gtl_different_type { typedef typename gtl_not<typename gtl_same_type<T, T2>::type>::type type; }; struct manhattan_domain {}; struct forty_five_domain {}; struct general_domain {}; template <typename T> struct geometry_domain { typedef general_domain type; }; template <typename domain_type, typename coordinate_type> struct area_type_by_domain { typedef typename coordinate_traits<coordinate_type>::area_type type; }; template <typename coordinate_type> struct area_type_by_domain<manhattan_domain, coordinate_type> { typedef typename coordinate_traits<coordinate_type>::manhattan_area_type type; }; template<bool E, class R = void> struct enable_if_ { typedef R type; }; template<class R> struct enable_if_<false, R> { }; template<class E, class R = void> struct enable_if : enable_if_<E::value, R> { }; struct y_c_edist : gtl_yes {}; template <typename coordinate_type_1, typename coordinate_type_2> typename enable_if< typename gtl_and_3<y_c_edist, typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type, typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type>::type, typename coordinate_traits<coordinate_type_1>::coordinate_difference>::type euclidean_distance(const coordinate_type_1& lvalue, const coordinate_type_2& rvalue) { typedef typename coordinate_traits<coordinate_type_1>::coordinate_difference Unit; return (lvalue < rvalue) ? (Unit)rvalue - (Unit)lvalue : (Unit)lvalue - (Unit)rvalue; } // predicated_swap swaps a and b if pred is true // predicated_swap is guarenteed to behave the same as // if(pred){ // T tmp = a; // a = b; // b = tmp; // } // but will not generate a branch instruction. // predicated_swap always creates a temp copy of a, but does not // create more than one temp copy of an input. // predicated_swap can be used to optimize away branch instructions in C++ template <class T> inline bool predicated_swap(const bool& pred, T& a, T& b) { const T tmp = a; const T* input[2] = {&b, &tmp}; a = *input[!pred]; b = *input[pred]; return pred; } enum direction_1d_enum { LOW = 0, HIGH = 1, LEFT = 0, RIGHT = 1, CLOCKWISE = 0, COUNTERCLOCKWISE = 1, REVERSE = 0, FORWARD = 1, NEGATIVE = 0, POSITIVE = 1 }; enum orientation_2d_enum { HORIZONTAL = 0, VERTICAL = 1 }; enum direction_2d_enum { WEST = 0, EAST = 1, SOUTH = 2, NORTH = 3 }; enum orientation_3d_enum { PROXIMAL = 2 }; enum direction_3d_enum { DOWN = 4, UP = 5 }; enum winding_direction { clockwise_winding = 0, counterclockwise_winding = 1, unknown_winding = 2 }; class direction_2d; class direction_3d; class orientation_2d; class direction_1d { private: unsigned int val_; explicit direction_1d(int d); public: inline direction_1d() : val_(LOW) {} inline direction_1d(const direction_1d& that) : val_(that.val_) {} inline direction_1d(const direction_1d_enum val) : val_(val) {} explicit inline direction_1d(const direction_2d& that); explicit inline direction_1d(const direction_3d& that); inline direction_1d& operator = (const direction_1d& d) { val_ = d.val_; return * this; } inline bool operator==(direction_1d d) const { return (val_ == d.val_); } inline bool operator!=(direction_1d d) const { return !((*this) == d); } inline unsigned int to_int(void) const { return val_; } inline direction_1d& backward() { val_ ^= 1; return *this; } inline int get_sign() const { return val_ * 2 - 1; } }; class direction_2d; class orientation_2d { private: unsigned int val_; explicit inline orientation_2d(int o); public: inline orientation_2d() : val_(HORIZONTAL) {} inline orientation_2d(const orientation_2d& ori) : val_(ori.val_) {} inline orientation_2d(const orientation_2d_enum val) : val_(val) {} explicit inline orientation_2d(const direction_2d& that); inline orientation_2d& operator=(const orientation_2d& ori) { val_ = ori.val_; return * this; } inline bool operator==(orientation_2d that) const { return (val_ == that.val_); } inline bool operator!=(orientation_2d that) const { return (val_ != that.val_); } inline unsigned int to_int() const { return (val_); } inline void turn_90() { val_ = val_^ 1; } inline orientation_2d get_perpendicular() const { orientation_2d retval = *this; retval.turn_90(); return retval; } inline direction_2d get_direction(direction_1d dir) const; }; class direction_2d { private: int val_; public: inline direction_2d() : val_(WEST) {} inline direction_2d(const direction_2d& that) : val_(that.val_) {} inline direction_2d(const direction_2d_enum val) : val_(val) {} inline direction_2d& operator=(const direction_2d& d) { val_ = d.val_; return * this; } inline ~direction_2d() { } inline bool operator==(direction_2d d) const { return (val_ == d.val_); } inline bool operator!=(direction_2d d) const { return !((*this) == d); } inline bool operator< (direction_2d d) const { return (val_ < d.val_); } inline bool operator<=(direction_2d d) const { return (val_ <= d.val_); } inline bool operator> (direction_2d d) const { return (val_ > d.val_); } inline bool operator>=(direction_2d d) const { return (val_ >= d.val_); } // Casting to int inline unsigned int to_int(void) const { return val_; } inline direction_2d backward() const { // flip the LSB, toggles 0 - 1 and 2 - 3 return direction_2d(direction_2d_enum(val_ ^ 1)); } // Returns a direction 90 degree left (LOW) or right(HIGH) to this one inline direction_2d turn(direction_1d t) const { return direction_2d(direction_2d_enum(val_ ^ 3 ^ (val_ >> 1) ^ t.to_int())); } // Returns a direction 90 degree left to this one inline direction_2d left() const {return turn(HIGH);} // Returns a direction 90 degree right to this one inline direction_2d right() const {return turn(LOW);} // N, E are positive, S, W are negative inline bool is_positive() const {return (val_ & 1);} inline bool is_negative() const {return !is_positive();} inline int get_sign() const {return ((is_positive()) << 1) -1;} }; direction_1d::direction_1d(const direction_2d& that) : val_(that.to_int() & 1) {} orientation_2d::orientation_2d(const direction_2d& that) : val_(that.to_int() >> 1) {} direction_2d orientation_2d::get_direction(direction_1d dir) const { return direction_2d(direction_2d_enum((val_ << 1) + dir.to_int())); } class orientation_3d { private: unsigned int val_; explicit inline orientation_3d(int o); public: inline orientation_3d() : val_((int)HORIZONTAL) {} inline orientation_3d(const orientation_3d& ori) : val_(ori.val_) {} inline orientation_3d(orientation_2d ori) : val_(ori.to_int()) {} inline orientation_3d(const orientation_3d_enum val) : val_(val) {} explicit inline orientation_3d(const direction_2d& that); explicit inline orientation_3d(const direction_3d& that); inline ~orientation_3d() { } inline orientation_3d& operator=(const orientation_3d& ori) { val_ = ori.val_; return * this; } inline bool operator==(orientation_3d that) const { return (val_ == that.val_); } inline bool operator!=(orientation_3d that) const { return (val_ != that.val_); } inline unsigned int to_int() const { return (val_); } inline direction_3d get_direction(direction_1d dir) const; }; class direction_3d { private: int val_; public: inline direction_3d() : val_(WEST) {} inline direction_3d(direction_2d that) : val_(that.to_int()) {} inline direction_3d(const direction_3d& that) : val_(that.val_) {} inline direction_3d(const direction_2d_enum val) : val_(val) {} inline direction_3d(const direction_3d_enum val) : val_(val) {} inline direction_3d& operator=(direction_3d d) { val_ = d.val_; return * this; } inline ~direction_3d() { } inline bool operator==(direction_3d d) const { return (val_ == d.val_); } inline bool operator!=(direction_3d d) const { return !((*this) == d); } inline bool operator< (direction_3d d) const { return (val_ < d.val_); } inline bool operator<=(direction_3d d) const { return (val_ <= d.val_); } inline bool operator> (direction_3d d) const { return (val_ > d.val_); } inline bool operator>=(direction_3d d) const { return (val_ >= d.val_); } // Casting to int inline unsigned int to_int(void) const { return val_; } inline direction_3d backward() const { // flip the LSB, toggles 0 - 1 and 2 - 3 and 4 - 5 return direction_2d(direction_2d_enum(val_ ^ 1)); } // N, E, U are positive, S, W, D are negative inline bool is_positive() const {return (val_ & 1);} inline bool is_negative() const {return !is_positive();} inline int get_sign() const {return ((is_positive()) << 1) -1;} }; direction_1d::direction_1d(const direction_3d& that) : val_(that.to_int() & 1) {} orientation_3d::orientation_3d(const direction_3d& that) : val_(that.to_int() >> 1) {} orientation_3d::orientation_3d(const direction_2d& that) : val_(that.to_int() >> 1) {} direction_3d orientation_3d::get_direction(direction_1d dir) const { return direction_3d(direction_3d_enum((val_ << 1) + dir.to_int())); } } } #endif segment_utils.hpp 0000644 00000011543 15125572616 0010155 0 ustar 00 /* Copyright 2012 Lucanus Simonson 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_SEGMENT_UTILS_HPP #define BOOST_POLYGON_SEGMENT_UTILS_HPP #include <iterator> #include <set> #include <vector> #include "detail/scan_arbitrary.hpp" #include "isotropy.hpp" #include "rectangle_concept.hpp" #include "segment_concept.hpp" namespace boost { namespace polygon { template <typename Segment, typename SegmentIterator> typename enable_if< typename gtl_and< typename gtl_if< typename is_segment_concept< typename geometry_concept< typename std::iterator_traits<SegmentIterator>::value_type >::type >::type >::type, typename gtl_if< typename is_segment_concept< typename geometry_concept<Segment>::type >::type >::type >::type, void >::type intersect_segments( std::vector<std::pair<std::size_t, Segment> >& result, SegmentIterator first, SegmentIterator last) { typedef typename segment_traits<Segment>::coordinate_type Unit; typedef typename scanline_base<Unit>::Point Point; typedef typename scanline_base<Unit>::half_edge half_edge; typedef int segment_id; std::vector<std::pair<half_edge, segment_id> > half_edges; std::vector<std::pair<half_edge, segment_id> > half_edges_out; segment_id id_in = 0; half_edges.reserve(std::distance(first, last)); for (; first != last; ++first) { Point l, h; assign(l, low(*first)); assign(h, high(*first)); half_edges.push_back(std::make_pair(half_edge(l, h), id_in++)); } half_edges_out.reserve(half_edges.size()); // Apparently no need to pre-sort data when calling validate_scan. if (half_edges.size() != 0) { line_intersection<Unit>::validate_scan( half_edges_out, half_edges.begin(), half_edges.end()); } result.reserve(result.size() + half_edges_out.size()); for (std::size_t i = 0; i < half_edges_out.size(); ++i) { std::size_t id = (std::size_t)(half_edges_out[i].second); Point l = half_edges_out[i].first.first; Point h = half_edges_out[i].first.second; result.push_back(std::make_pair(id, construct<Segment>(l, h))); } } template <typename SegmentContainer, typename SegmentIterator> typename enable_if< typename gtl_and< typename gtl_if< typename is_segment_concept< typename geometry_concept< typename std::iterator_traits<SegmentIterator>::value_type >::type >::type >::type, typename gtl_if< typename is_segment_concept< typename geometry_concept< typename SegmentContainer::value_type >::type >::type >::type >::type, void >::type intersect_segments( SegmentContainer& result, SegmentIterator first, SegmentIterator last) { typedef typename SegmentContainer::value_type segment_type; typedef typename segment_traits<segment_type>::coordinate_type Unit; typedef typename scanline_base<Unit>::Point Point; typedef typename scanline_base<Unit>::half_edge half_edge; typedef int segment_id; std::vector<std::pair<half_edge, segment_id> > half_edges; std::vector<std::pair<half_edge, segment_id> > half_edges_out; segment_id id_in = 0; half_edges.reserve(std::distance(first, last)); for (; first != last; ++first) { Point l, h; assign(l, low(*first)); assign(h, high(*first)); half_edges.push_back(std::make_pair(half_edge(l, h), id_in++)); } half_edges_out.reserve(half_edges.size()); // Apparently no need to pre-sort data when calling validate_scan. if (half_edges.size() != 0) { line_intersection<Unit>::validate_scan( half_edges_out, half_edges.begin(), half_edges.end()); } result.reserve(result.size() + half_edges_out.size()); for (std::size_t i = 0; i < half_edges_out.size(); ++i) { Point l = half_edges_out[i].first.first; Point h = half_edges_out[i].first.second; result.push_back(construct<segment_type>(l, h)); } } template <typename Rectangle, typename SegmentIterator> typename enable_if< typename gtl_and< typename gtl_if< typename is_rectangle_concept< typename geometry_concept<Rectangle>::type >::type >::type, typename gtl_if< typename is_segment_concept< typename geometry_concept< typename std::iterator_traits<SegmentIterator>::value_type >::type >::type >::type >::type, bool >::type envelope_segments( Rectangle& rect, SegmentIterator first, SegmentIterator last) { for (SegmentIterator it = first; it != last; ++it) { if (it == first) { set_points(rect, low(*it), high(*it)); } else { encompass(rect, low(*it)); encompass(rect, high(*it)); } } return first != last; } } // polygon } // boost #endif // BOOST_POLYGON_SEGMENT_UTILS_HPP
| ver. 1.6 |
Github
|
.
| PHP 8.2.30 | ??????????? ?????????: 0.04 |
proxy
|
phpinfo
|
???????????