/* 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 <boost/polygon/polygon.hpp> #include <list> #include <time.h> #include <cassert> #include <deque> #include <iostream> 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 <typename PolygonSet> void test_polygon_set() { using namespace gtl; PolygonSet ps; ps += rectangle_data<int>(0, 0, 10, 10); PolygonSet ps2; ps2 += rectangle_data<int>(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<int> 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<CPoint> { typedef point_concept type; }; template <> struct point_traits<CPoint> { 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<CPoint> { 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<CPoint> 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<CPolygon>{ typedef polygon_concept type; }; template <> struct polygon_traits<CPolygon> { 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<CPolygon> { //expects stl style iterators template <typename iT> 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<CPolygon> 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<CPolygonSet> { typedef polygon_set_concept type; }; //next we map to the concept through traits template <> struct polygon_set_traits<CPolygonSet> { 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<CPolygonSet> { template <typename input_iterator_type> 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<int> 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<CPolygonSet>(); long long c2 = clock(); for(int i = 0; i < 1000; ++i) test_polygon_set<gtl::polygon_set_data<int> >(); 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