/* 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 #include #include #include #include #include namespace gtl = boost::polygon; using namespace boost::polygon::operators; //once again we make our usage of the library generic //and parameterize it on the polygon set type template void test_polygon_set() { using namespace gtl; PolygonSet ps; ps += rectangle_data(0, 0, 10, 10); PolygonSet ps2; ps2 += rectangle_data(5, 5, 15, 15); PolygonSet ps3; assign(ps3, ps * ps2); PolygonSet ps4; ps4 += ps + ps2; assert(area(ps4) == area(ps) + area(ps2) - area(ps3)); assert(equivalence((ps + ps2) - (ps * ps2), ps ^ ps2)); rectangle_data rect; assert(extents(rect, ps ^ ps2)); assert(area(rect) == 225); assert(area(rect ^ (ps ^ ps2)) == area(rect) - area(ps ^ ps2)); } //first thing is first, lets include all the code from previous examples //the CPoint example struct CPoint { int x; int y; }; namespace boost { namespace polygon { template <> struct geometry_concept { typedef point_concept type; }; template <> struct point_traits { typedef int coordinate_type; static inline coordinate_type get(const CPoint& point, orientation_2d orient) { if(orient == HORIZONTAL) return point.x; return point.y; } }; template <> struct point_mutable_traits { typedef int coordinate_type; static inline void set(CPoint& point, orientation_2d orient, int value) { if(orient == HORIZONTAL) point.x = value; else point.y = value; } static inline CPoint construct(int x_value, int y_value) { CPoint retval; retval.x = x_value; retval.y = y_value; return retval; } }; } } //the CPolygon example typedef std::list CPolygon; //we need to specialize our polygon concept mapping in boost polygon namespace boost { namespace polygon { //first register CPolygon as a polygon_concept type template <> struct geometry_concept{ typedef polygon_concept type; }; template <> struct polygon_traits { typedef int coordinate_type; typedef CPolygon::const_iterator iterator_type; typedef CPoint point_type; // Get the begin iterator static inline iterator_type begin_points(const CPolygon& t) { return t.begin(); } // Get the end iterator static inline iterator_type end_points(const CPolygon& t) { return t.end(); } // Get the number of sides of the polygon static inline std::size_t size(const CPolygon& t) { return t.size(); } // Get the winding direction of the polygon static inline winding_direction winding(const CPolygon& t) { return unknown_winding; } }; template <> struct polygon_mutable_traits { //expects stl style iterators template static inline CPolygon& set_points(CPolygon& t, iT input_begin, iT input_end) { t.clear(); while(input_begin != input_end) { t.push_back(CPoint()); gtl::assign(t.back(), *input_begin); ++input_begin; } return t; } }; } } //OK, finally we get to declare our own polygon set type typedef std::deque CPolygonSet; //deque isn't automatically a polygon set in the library //because it is a standard container there is a shortcut //for mapping it to polygon set concept, but I'll do it //the long way that you would use in the general case. namespace boost { namespace polygon { //first we register CPolygonSet as a polygon set template <> struct geometry_concept { typedef polygon_set_concept type; }; //next we map to the concept through traits template <> struct polygon_set_traits { typedef int coordinate_type; typedef CPolygonSet::const_iterator iterator_type; typedef CPolygonSet operator_arg_type; static inline iterator_type begin(const CPolygonSet& polygon_set) { return polygon_set.begin(); } static inline iterator_type end(const CPolygonSet& polygon_set) { return polygon_set.end(); } //don't worry about these, just return false from them static inline bool clean(const CPolygonSet& polygon_set) { return false; } static inline bool sorted(const CPolygonSet& polygon_set) { return false; } }; template <> struct polygon_set_mutable_traits { template static inline void set(CPolygonSet& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { polygon_set.clear(); //this is kind of cheesy. I am copying the unknown input geometry //into my own polygon set and then calling get to populate the //deque polygon_set_data ps; ps.insert(input_begin, input_end); ps.get(polygon_set); //if you had your own odd-ball polygon set you would probably have //to iterate through each polygon at this point and do something //extra } }; } } int main() { long long c1 = clock(); for(int i = 0; i < 1000; ++i) test_polygon_set(); long long c2 = clock(); for(int i = 0; i < 1000; ++i) test_polygon_set >(); long long c3 = clock(); long long diff1 = c2 - c1; long long diff2 = c3 - c2; if(diff1 > 0 && diff2) std::cout << "library polygon_set_data is " << float(diff1)/float(diff2) << "X faster than custom polygon set deque of CPolygon" << std::endl; else std::cout << "operation was too fast" << std::endl; return 0; } //Now you know how to map your own data type to polygon set concept //Now you also know how to make your application code that operates on geometry //data type agnostic from point through polygon set