...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
/*
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> {
   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
Â
Copyright: | Copyright © Intel Corporation 2008-2010. |
---|---|
License: | 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) |