polygon_set_data.hpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
  1. /*
  2. Copyright 2008 Intel Corporation
  3. Use, modification and distribution are subject to the Boost Software License,
  4. Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. http://www.boost.org/LICENSE_1_0.txt).
  6. */
  7. #ifndef BOOST_POLYGON_POLYGON_SET_DATA_HPP
  8. #define BOOST_POLYGON_POLYGON_SET_DATA_HPP
  9. #include "polygon_45_set_data.hpp"
  10. #include "polygon_45_set_concept.hpp"
  11. #include "polygon_traits.hpp"
  12. #include "detail/polygon_arbitrary_formation.hpp"
  13. namespace boost { namespace polygon {
  14. // utility function to round coordinate types down
  15. // rounds down for both negative and positive numbers
  16. // intended really for integer type T (does not make sense for float)
  17. template <typename T>
  18. static inline T round_down(double val) {
  19. T rounded_val = (T)(val);
  20. if(val < (double)rounded_val)
  21. --rounded_val;
  22. return rounded_val;
  23. }
  24. template <typename T>
  25. static inline point_data<T> round_down(point_data<double> v) {
  26. return point_data<T>(round_down<T>(v.x()),round_down<T>(v.y()));
  27. }
  28. //foward declare view
  29. template <typename ltype, typename rtype, int op_type> class polygon_set_view;
  30. template <typename T>
  31. class polygon_set_data {
  32. public:
  33. typedef T coordinate_type;
  34. typedef point_data<T> point_type;
  35. typedef std::pair<point_type, point_type> edge_type;
  36. typedef std::pair<edge_type, int> element_type;
  37. typedef std::vector<element_type> value_type;
  38. typedef typename value_type::const_iterator iterator_type;
  39. typedef polygon_set_data operator_arg_type;
  40. // default constructor
  41. inline polygon_set_data() : data_(), dirty_(false), unsorted_(false), is_45_(true) {}
  42. // constructor from an iterator pair over edge data
  43. template <typename iT>
  44. inline polygon_set_data(iT input_begin, iT input_end) : data_(), dirty_(false), unsorted_(false), is_45_(true) {
  45. for( ; input_begin != input_end; ++input_begin) { insert(*input_begin); }
  46. }
  47. // copy constructor
  48. inline polygon_set_data(const polygon_set_data& that) :
  49. data_(that.data_), dirty_(that.dirty_), unsorted_(that.unsorted_), is_45_(that.is_45_) {}
  50. // copy constructor
  51. template <typename ltype, typename rtype, int op_type>
  52. inline polygon_set_data(const polygon_set_view<ltype, rtype, op_type>& that);
  53. // destructor
  54. inline ~polygon_set_data() {}
  55. // assignement operator
  56. inline polygon_set_data& operator=(const polygon_set_data& that) {
  57. if(this == &that) return *this;
  58. data_ = that.data_;
  59. dirty_ = that.dirty_;
  60. unsorted_ = that.unsorted_;
  61. is_45_ = that.is_45_;
  62. return *this;
  63. }
  64. template <typename ltype, typename rtype, int op_type>
  65. inline polygon_set_data& operator=(const polygon_set_view<ltype, rtype, op_type>& geometry) {
  66. (*this) = geometry.value();
  67. dirty_ = false;
  68. unsorted_ = false;
  69. return *this;
  70. }
  71. template <typename geometry_object>
  72. inline polygon_set_data& operator=(const geometry_object& geometry) {
  73. data_.clear();
  74. insert(geometry);
  75. return *this;
  76. }
  77. // insert iterator range
  78. inline void insert(iterator_type input_begin, iterator_type input_end, bool is_hole = false) {
  79. if(input_begin == input_end || (!data_.empty() && &(*input_begin) == &(*(data_.begin())))) return;
  80. dirty_ = true;
  81. unsorted_ = true;
  82. while(input_begin != input_end) {
  83. insert(*input_begin, is_hole);
  84. ++input_begin;
  85. }
  86. }
  87. // insert iterator range
  88. template <typename iT>
  89. inline void insert(iT input_begin, iT input_end, bool is_hole = false) {
  90. if(input_begin == input_end) return;
  91. for(; input_begin != input_end; ++input_begin) {
  92. insert(*input_begin, is_hole);
  93. }
  94. }
  95. template <typename geometry_type>
  96. inline void insert(const geometry_type& geometry_object, bool is_hole = false) {
  97. insert(geometry_object, is_hole, typename geometry_concept<geometry_type>::type());
  98. }
  99. template <typename polygon_type>
  100. inline void insert(const polygon_type& polygon_object, bool is_hole, polygon_concept ) {
  101. insert_vertex_sequence(begin_points(polygon_object), end_points(polygon_object), winding(polygon_object), is_hole);
  102. }
  103. inline void insert(const polygon_set_data& ps, bool is_hole = false) {
  104. insert(ps.data_.begin(), ps.data_.end(), is_hole);
  105. }
  106. template <typename polygon_45_set_type>
  107. inline void insert(const polygon_45_set_type& ps, bool is_hole, polygon_45_set_concept) {
  108. std::vector<polygon_45_with_holes_data<typename polygon_45_set_traits<polygon_45_set_type>::coordinate_type> > polys;
  109. assign(polys, ps);
  110. insert(polys.begin(), polys.end(), is_hole);
  111. }
  112. template <typename polygon_90_set_type>
  113. inline void insert(const polygon_90_set_type& ps, bool is_hole, polygon_90_set_concept) {
  114. std::vector<polygon_90_with_holes_data<typename polygon_90_set_traits<polygon_90_set_type>::coordinate_type> > polys;
  115. assign(polys, ps);
  116. insert(polys.begin(), polys.end(), is_hole);
  117. }
  118. template <typename polygon_type>
  119. inline void insert(const polygon_type& polygon_object, bool is_hole, polygon_45_concept ) {
  120. insert(polygon_object, is_hole, polygon_concept()); }
  121. template <typename polygon_type>
  122. inline void insert(const polygon_type& polygon_object, bool is_hole, polygon_90_concept ) {
  123. insert(polygon_object, is_hole, polygon_concept()); }
  124. template <typename polygon_with_holes_type>
  125. inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole,
  126. polygon_with_holes_concept ) {
  127. insert(polygon_with_holes_object, is_hole, polygon_concept());
  128. for(typename polygon_with_holes_traits<polygon_with_holes_type>::iterator_holes_type itr =
  129. begin_holes(polygon_with_holes_object);
  130. itr != end_holes(polygon_with_holes_object); ++itr) {
  131. insert(*itr, !is_hole, polygon_concept());
  132. }
  133. }
  134. template <typename polygon_with_holes_type>
  135. inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole,
  136. polygon_45_with_holes_concept ) {
  137. insert(polygon_with_holes_object, is_hole, polygon_with_holes_concept()); }
  138. template <typename polygon_with_holes_type>
  139. inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole,
  140. polygon_90_with_holes_concept ) {
  141. insert(polygon_with_holes_object, is_hole, polygon_with_holes_concept()); }
  142. template <typename rectangle_type>
  143. inline void insert(const rectangle_type& rectangle_object, bool is_hole, rectangle_concept ) {
  144. polygon_90_data<coordinate_type> poly;
  145. assign(poly, rectangle_object);
  146. insert(poly, is_hole, polygon_concept());
  147. }
  148. inline void insert_clean(const element_type& edge, bool is_hole = false) {
  149. if( ! scanline_base<coordinate_type>::is_45_degree(edge.first) &&
  150. ! scanline_base<coordinate_type>::is_horizontal(edge.first) &&
  151. ! scanline_base<coordinate_type>::is_vertical(edge.first) ) is_45_ = false;
  152. data_.push_back(edge);
  153. if(data_.back().first.second < data_.back().first.first) {
  154. std::swap(data_.back().first.second, data_.back().first.first);
  155. data_.back().second *= -1;
  156. }
  157. if(is_hole)
  158. data_.back().second *= -1;
  159. }
  160. inline void insert(const element_type& edge, bool is_hole = false) {
  161. insert_clean(edge, is_hole);
  162. dirty_ = true;
  163. unsorted_ = true;
  164. }
  165. template <class iT>
  166. inline void insert_vertex_sequence(iT begin_vertex, iT end_vertex, direction_1d winding, bool is_hole) {
  167. bool first_iteration = true;
  168. point_type first_point;
  169. point_type previous_point;
  170. point_type current_point;
  171. direction_1d winding_dir = winding;
  172. int multiplier = winding_dir == COUNTERCLOCKWISE ? 1 : -1;
  173. if(is_hole) multiplier *= -1;
  174. for( ; begin_vertex != end_vertex; ++begin_vertex) {
  175. assign(current_point, *begin_vertex);
  176. if(first_iteration) {
  177. first_iteration = false;
  178. first_point = previous_point = current_point;
  179. } else {
  180. if(previous_point != current_point) {
  181. element_type elem(edge_type(previous_point, current_point),
  182. ( previous_point.get(HORIZONTAL) == current_point.get(HORIZONTAL) ? -1 : 1) * multiplier);
  183. insert_clean(elem);
  184. }
  185. }
  186. previous_point = current_point;
  187. }
  188. current_point = first_point;
  189. if(!first_iteration) {
  190. if(previous_point != current_point) {
  191. element_type elem(edge_type(previous_point, current_point),
  192. ( previous_point.get(HORIZONTAL) == current_point.get(HORIZONTAL) ? -1 : 1) * multiplier);
  193. insert_clean(elem);
  194. }
  195. dirty_ = true;
  196. unsorted_ = true;
  197. }
  198. }
  199. template <typename output_container>
  200. inline void get(output_container& output) const {
  201. get_dispatch(output, typename geometry_concept<typename output_container::value_type>::type());
  202. }
  203. // append to the container cT with polygons of three or four verticies
  204. // slicing orientation is vertical
  205. template <class cT>
  206. void get_trapezoids(cT& container) const {
  207. clean();
  208. trapezoid_arbitrary_formation<coordinate_type> pf;
  209. typedef typename polygon_arbitrary_formation<coordinate_type>::vertex_half_edge vertex_half_edge;
  210. std::vector<vertex_half_edge> data;
  211. for(iterator_type itr = data_.begin(); itr != data_.end(); ++itr){
  212. data.push_back(vertex_half_edge((*itr).first.first, (*itr).first.second, (*itr).second));
  213. data.push_back(vertex_half_edge((*itr).first.second, (*itr).first.first, -1 * (*itr).second));
  214. }
  215. polygon_sort(data.begin(), data.end());
  216. pf.scan(container, data.begin(), data.end());
  217. //std::cout << "DONE FORMING POLYGONS\n";
  218. }
  219. // append to the container cT with polygons of three or four verticies
  220. template <class cT>
  221. void get_trapezoids(cT& container, orientation_2d slicing_orientation) const {
  222. if(slicing_orientation == VERTICAL) {
  223. get_trapezoids(container);
  224. } else {
  225. polygon_set_data<T> ps(*this);
  226. ps.transform(axis_transformation(axis_transformation::SWAP_XY));
  227. cT result;
  228. ps.get_trapezoids(result);
  229. for(typename cT::iterator itr = result.begin(); itr != result.end(); ++itr) {
  230. ::boost::polygon::transform(*itr, axis_transformation(axis_transformation::SWAP_XY));
  231. }
  232. container.insert(container.end(), result.begin(), result.end());
  233. }
  234. }
  235. // equivalence operator
  236. inline bool operator==(const polygon_set_data& p) const;
  237. // inequivalence operator
  238. inline bool operator!=(const polygon_set_data& p) const {
  239. return !((*this) == p);
  240. }
  241. // get iterator to begin vertex data
  242. inline iterator_type begin() const {
  243. return data_.begin();
  244. }
  245. // get iterator to end vertex data
  246. inline iterator_type end() const {
  247. return data_.end();
  248. }
  249. const value_type& value() const {
  250. return data_;
  251. }
  252. // clear the contents of the polygon_set_data
  253. inline void clear() { data_.clear(); dirty_ = unsorted_ = false; }
  254. // find out if Polygon set is empty
  255. inline bool empty() const { return data_.empty(); }
  256. // get the Polygon set size in vertices
  257. inline std::size_t size() const { clean(); return data_.size(); }
  258. // get the current Polygon set capacity in vertices
  259. inline std::size_t capacity() const { return data_.capacity(); }
  260. // reserve size of polygon set in vertices
  261. inline void reserve(std::size_t size) { return data_.reserve(size); }
  262. // find out if Polygon set is sorted
  263. inline bool sorted() const { return !unsorted_; }
  264. // find out if Polygon set is clean
  265. inline bool dirty() const { return dirty_; }
  266. void clean() const;
  267. void sort() const{
  268. if(unsorted_) {
  269. polygon_sort(data_.begin(), data_.end());
  270. unsorted_ = false;
  271. }
  272. }
  273. template <typename input_iterator_type>
  274. void set(input_iterator_type input_begin, input_iterator_type input_end) {
  275. clear();
  276. reserve(std::distance(input_begin,input_end));
  277. insert(input_begin, input_end);
  278. dirty_ = true;
  279. unsorted_ = true;
  280. }
  281. void set(const value_type& value) {
  282. data_ = value;
  283. dirty_ = true;
  284. unsorted_ = true;
  285. }
  286. template <typename rectangle_type>
  287. bool extents(rectangle_type& rect) {
  288. clean();
  289. if(empty()) return false;
  290. bool first_iteration = true;
  291. for(iterator_type itr = begin();
  292. itr != end(); ++itr) {
  293. rectangle_type edge_box;
  294. set_points(edge_box, (*itr).first.first, (*itr).first.second);
  295. if(first_iteration)
  296. rect = edge_box;
  297. else
  298. encompass(rect, edge_box);
  299. first_iteration = false;
  300. }
  301. return true;
  302. }
  303. inline polygon_set_data&
  304. resize(coordinate_type resizing, bool corner_fill_arc = false, unsigned int num_circle_segments=0);
  305. template <typename transform_type>
  306. inline polygon_set_data&
  307. transform(const transform_type& tr) {
  308. std::vector<polygon_with_holes_data<T> > polys;
  309. get(polys);
  310. clear();
  311. for(std::size_t i = 0 ; i < polys.size(); ++i) {
  312. ::boost::polygon::transform(polys[i], tr);
  313. insert(polys[i]);
  314. }
  315. unsorted_ = true;
  316. dirty_ = true;
  317. return *this;
  318. }
  319. inline polygon_set_data&
  320. scale_up(typename coordinate_traits<coordinate_type>::unsigned_area_type factor) {
  321. for(typename value_type::iterator itr = data_.begin(); itr != data_.end(); ++itr) {
  322. ::boost::polygon::scale_up((*itr).first.first, factor);
  323. ::boost::polygon::scale_up((*itr).first.second, factor);
  324. }
  325. return *this;
  326. }
  327. inline polygon_set_data&
  328. scale_down(typename coordinate_traits<coordinate_type>::unsigned_area_type factor) {
  329. for(typename value_type::iterator itr = data_.begin(); itr != data_.end(); ++itr) {
  330. bool vb = (*itr).first.first.x() == (*itr).first.second.x();
  331. ::boost::polygon::scale_down((*itr).first.first, factor);
  332. ::boost::polygon::scale_down((*itr).first.second, factor);
  333. bool va = (*itr).first.first.x() == (*itr).first.second.x();
  334. if(!vb && va) {
  335. (*itr).second *= -1;
  336. }
  337. }
  338. unsorted_ = true;
  339. dirty_ = true;
  340. return *this;
  341. }
  342. template <typename scaling_type>
  343. inline polygon_set_data& scale(polygon_set_data& polygon_set,
  344. const scaling_type& scaling) {
  345. for(typename value_type::iterator itr = begin(); itr != end(); ++itr) {
  346. bool vb = (*itr).first.first.x() == (*itr).first.second.x();
  347. ::boost::polygon::scale((*itr).first.first, scaling);
  348. ::boost::polygon::scale((*itr).first.second, scaling);
  349. bool va = (*itr).first.first.x() == (*itr).first.second.x();
  350. if(!vb && va) {
  351. (*itr).second *= -1;
  352. }
  353. }
  354. unsorted_ = true;
  355. dirty_ = true;
  356. return *this;
  357. }
  358. static inline void compute_offset_edge(point_data<long double>& pt1, point_data<long double>& pt2,
  359. const point_data<long double>& prev_pt,
  360. const point_data<long double>& current_pt,
  361. long double distance, int multiplier) {
  362. long double dx = current_pt.x() - prev_pt.x();
  363. long double dy = current_pt.y() - prev_pt.y();
  364. long double edge_length = std::sqrt(dx*dx + dy*dy);
  365. long double dnx = dy;
  366. long double dny = -dx;
  367. dnx = dnx * (long double)distance / edge_length;
  368. dny = dny * (long double)distance / edge_length;
  369. pt1.x(prev_pt.x() + (long double)dnx * (long double)multiplier);
  370. pt2.x(current_pt.x() + (long double)dnx * (long double)multiplier);
  371. pt1.y(prev_pt.y() + (long double)dny * (long double)multiplier);
  372. pt2.y(current_pt.y() + (long double)dny * (long double)multiplier);
  373. }
  374. static inline void modify_pt(point_data<coordinate_type>& pt, const point_data<coordinate_type>& prev_pt,
  375. const point_data<coordinate_type>& current_pt, const point_data<coordinate_type>& next_pt,
  376. coordinate_type distance, coordinate_type multiplier) {
  377. std::pair<point_data<long double>, point_data<long double> > he1, he2;
  378. he1.first.x((long double)(prev_pt.x()));
  379. he1.first.y((long double)(prev_pt.y()));
  380. he1.second.x((long double)(current_pt.x()));
  381. he1.second.y((long double)(current_pt.y()));
  382. he2.first.x((long double)(current_pt.x()));
  383. he2.first.y((long double)(current_pt.y()));
  384. he2.second.x((long double)(next_pt.x()));
  385. he2.second.y((long double)(next_pt.y()));
  386. compute_offset_edge(he1.first, he1.second, prev_pt, current_pt, distance, multiplier);
  387. compute_offset_edge(he2.first, he2.second, current_pt, next_pt, distance, multiplier);
  388. typedef scanline_base<long double>::compute_intersection_pack pack;
  389. point_data<long double> rpt;
  390. point_data<long double> bisectorpt((he1.second.x()+he2.first.x())/2,
  391. (he1.second.y()+he2.first.y())/2);
  392. point_data<long double> orig_pt((long double)pt.x(), (long double)pt.y());
  393. if(euclidean_distance(bisectorpt, orig_pt) < distance/2) {
  394. if(!pack::compute_lazy_intersection(rpt, he1, he2, true, false)) {
  395. rpt = he1.second; //colinear offset edges use shared point
  396. }
  397. } else {
  398. if(!pack::compute_lazy_intersection(rpt, he1, std::pair<point_data<long double>, point_data<long double> >(orig_pt, bisectorpt), true, false)) {
  399. rpt = he1.second; //colinear offset edges use shared point
  400. }
  401. }
  402. pt.x((coordinate_type)(std::floor(rpt.x()+0.5)));
  403. pt.y((coordinate_type)(std::floor(rpt.y()+0.5)));
  404. }
  405. static void resize_poly_up(std::vector<point_data<coordinate_type> >& poly, coordinate_type distance, coordinate_type multiplier) {
  406. point_data<coordinate_type> first_pt = poly[0];
  407. point_data<coordinate_type> second_pt = poly[1];
  408. point_data<coordinate_type> prev_pt = poly[0];
  409. point_data<coordinate_type> current_pt = poly[1];
  410. for(std::size_t i = 2; i < poly.size()-1; ++i) {
  411. point_data<coordinate_type> next_pt = poly[i];
  412. modify_pt(poly[i-1], prev_pt, current_pt, next_pt, distance, multiplier);
  413. prev_pt = current_pt;
  414. current_pt = next_pt;
  415. }
  416. point_data<coordinate_type> next_pt = first_pt;
  417. modify_pt(poly[poly.size()-2], prev_pt, current_pt, next_pt, distance, multiplier);
  418. prev_pt = current_pt;
  419. current_pt = next_pt;
  420. next_pt = second_pt;
  421. modify_pt(poly[0], prev_pt, current_pt, next_pt, distance, multiplier);
  422. poly.back() = poly.front();
  423. }
  424. static bool resize_poly_down(std::vector<point_data<coordinate_type> >& poly, coordinate_type distance, coordinate_type multiplier) {
  425. std::vector<point_data<coordinate_type> > orig_poly(poly);
  426. rectangle_data<coordinate_type> extents_rectangle;
  427. set_points(extents_rectangle, poly[0], poly[0]);
  428. point_data<coordinate_type> first_pt = poly[0];
  429. point_data<coordinate_type> second_pt = poly[1];
  430. point_data<coordinate_type> prev_pt = poly[0];
  431. point_data<coordinate_type> current_pt = poly[1];
  432. encompass(extents_rectangle, current_pt);
  433. for(std::size_t i = 2; i < poly.size()-1; ++i) {
  434. point_data<coordinate_type> next_pt = poly[i];
  435. encompass(extents_rectangle, next_pt);
  436. modify_pt(poly[i-1], prev_pt, current_pt, next_pt, distance, multiplier);
  437. prev_pt = current_pt;
  438. current_pt = next_pt;
  439. }
  440. if(delta(extents_rectangle, HORIZONTAL) <= std::abs(2*distance))
  441. return false;
  442. if(delta(extents_rectangle, VERTICAL) <= std::abs(2*distance))
  443. return false;
  444. point_data<coordinate_type> next_pt = first_pt;
  445. modify_pt(poly[poly.size()-2], prev_pt, current_pt, next_pt, distance, multiplier);
  446. prev_pt = current_pt;
  447. current_pt = next_pt;
  448. next_pt = second_pt;
  449. modify_pt(poly[0], prev_pt, current_pt, next_pt, distance, multiplier);
  450. poly.back() = poly.front();
  451. //if the line segments formed between orignial and new points cross for an edge that edge inverts
  452. //if all edges invert the polygon should be discarded
  453. //if even one edge does not invert return true because the polygon is valid
  454. bool non_inverting_edge = false;
  455. for(std::size_t i = 1; i < poly.size(); ++i) {
  456. std::pair<point_data<coordinate_type>, point_data<coordinate_type> >
  457. he1(poly[i], orig_poly[i]),
  458. he2(poly[i-1], orig_poly[i-1]);
  459. if(!scanline_base<coordinate_type>::intersects(he1, he2)) {
  460. non_inverting_edge = true;
  461. break;
  462. }
  463. }
  464. return non_inverting_edge;
  465. }
  466. polygon_set_data&
  467. bloat(typename coordinate_traits<coordinate_type>::unsigned_area_type distance) {
  468. std::list<polygon_with_holes_data<coordinate_type> > polys;
  469. get(polys);
  470. clear();
  471. for(typename std::list<polygon_with_holes_data<coordinate_type> >::iterator itr = polys.begin();
  472. itr != polys.end(); ++itr) {
  473. resize_poly_up((*itr).self_.coords_, (coordinate_type)distance, (coordinate_type)1);
  474. insert_vertex_sequence((*itr).self_.begin(), (*itr).self_.end(), COUNTERCLOCKWISE, false); //inserts without holes
  475. for(typename std::list<polygon_data<coordinate_type> >::iterator itrh = (*itr).holes_.begin();
  476. itrh != (*itr).holes_.end(); ++itrh) {
  477. if(resize_poly_down((*itrh).coords_, (coordinate_type)distance, (coordinate_type)1)) {
  478. insert_vertex_sequence((*itrh).coords_.begin(), (*itrh).coords_.end(), CLOCKWISE, true);
  479. }
  480. }
  481. }
  482. return *this;
  483. }
  484. polygon_set_data&
  485. shrink(typename coordinate_traits<coordinate_type>::unsigned_area_type distance) {
  486. std::list<polygon_with_holes_data<coordinate_type> > polys;
  487. get(polys);
  488. clear();
  489. for(typename std::list<polygon_with_holes_data<coordinate_type> >::iterator itr = polys.begin();
  490. itr != polys.end(); ++itr) {
  491. if(resize_poly_down((*itr).self_.coords_, (coordinate_type)distance, (coordinate_type)-1)) {
  492. insert_vertex_sequence((*itr).self_.begin(), (*itr).self_.end(), COUNTERCLOCKWISE, false); //inserts without holes
  493. for(typename std::list<polygon_data<coordinate_type> >::iterator itrh = (*itr).holes_.begin();
  494. itrh != (*itr).holes_.end(); ++itrh) {
  495. resize_poly_up((*itrh).coords_, (coordinate_type)distance, (coordinate_type)-1);
  496. insert_vertex_sequence((*itrh).coords_.begin(), (*itrh).coords_.end(), CLOCKWISE, true);
  497. }
  498. }
  499. }
  500. return *this;
  501. }
  502. // TODO:: should be private
  503. template <typename geometry_type>
  504. inline polygon_set_data&
  505. insert_with_resize(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc=false, unsigned int num_circle_segments=0, bool hole = false) {
  506. return insert_with_resize_dispatch(poly, resizing, corner_fill_arc, num_circle_segments, hole, typename geometry_concept<geometry_type>::type());
  507. }
  508. template <typename geometry_type>
  509. inline polygon_set_data&
  510. insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole,
  511. polygon_with_holes_concept tag) {
  512. insert_with_resize_dispatch(poly, resizing, corner_fill_arc, num_circle_segments, hole, polygon_concept());
  513. for(typename polygon_with_holes_traits<geometry_type>::iterator_holes_type itr =
  514. begin_holes(poly); itr != end_holes(poly);
  515. ++itr) {
  516. insert_with_resize_dispatch(*itr, resizing, corner_fill_arc, num_circle_segments, !hole, polygon_concept());
  517. }
  518. return *this;
  519. }
  520. template <typename geometry_type>
  521. inline polygon_set_data&
  522. insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole,
  523. polygon_concept tag) {
  524. if (resizing==0)
  525. return *this;
  526. // one dimensional used to store CCW/CW flag
  527. //direction_1d wdir = winding(poly);
  528. // LOW==CLOCKWISE just faster to type
  529. // so > 0 is CCW
  530. //int multiplier = wdir == LOW ? -1 : 1;
  531. //std::cout<<" multiplier : "<<multiplier<<std::endl;
  532. //if(hole) resizing *= -1;
  533. direction_1d resize_wdir = resizing>0?COUNTERCLOCKWISE:CLOCKWISE;
  534. typedef typename polygon_data<T>::iterator_type piterator;
  535. piterator first, second, third, end, real_end;
  536. real_end = end_points(poly);
  537. third = begin_points(poly);
  538. first = third;
  539. if(first == real_end) return *this;
  540. ++third;
  541. if(third == real_end) return *this;
  542. second = end = third;
  543. ++third;
  544. if(third == real_end) return *this;
  545. // for 1st corner
  546. std::vector<point_data<T> > first_pts;
  547. std::vector<point_data<T> > all_pts;
  548. direction_1d first_wdir = CLOCKWISE;
  549. // for all corners
  550. polygon_set_data<T> sizingSet;
  551. bool sizing_sign = resizing<0;
  552. bool prev_concave = true;
  553. point_data<T> prev_point;
  554. //int iCtr=0;
  555. //insert minkofski shapes on edges and corners
  556. do { // REAL WORK IS HERE
  557. //first, second and third point to points in correct CCW order
  558. // check if convex or concave case
  559. point_data<coordinate_type> normal1( second->y()-first->y(), first->x()-second->x());
  560. point_data<coordinate_type> normal2( third->y()-second->y(), second->x()-third->x());
  561. double direction = normal1.x()*normal2.y()- normal2.x()*normal1.y();
  562. bool convex = direction>0;
  563. bool treat_as_concave = !convex;
  564. if(sizing_sign)
  565. treat_as_concave = convex;
  566. point_data<double> v;
  567. assign(v, normal1);
  568. double s2 = (v.x()*v.x()+v.y()*v.y());
  569. double s = std::sqrt(s2)/resizing;
  570. v = point_data<double>(v.x()/s,v.y()/s);
  571. point_data<T> curr_prev;
  572. if (prev_concave)
  573. //TODO missing round_down()
  574. curr_prev = point_data<T>(first->x()+v.x(),first->y()+v.y());
  575. else
  576. curr_prev = prev_point;
  577. // around concave corners - insert rectangle
  578. // if previous corner is concave it's point info may be ignored
  579. if ( treat_as_concave) {
  580. std::vector<point_data<T> > pts;
  581. pts.push_back(point_data<T>(second->x()+v.x(),second->y()+v.y()));
  582. pts.push_back(*second);
  583. pts.push_back(*first);
  584. pts.push_back(point_data<T>(curr_prev));
  585. if (first_pts.size()){
  586. sizingSet.insert_vertex_sequence(pts.begin(),pts.end(), resize_wdir,false);
  587. }else {
  588. first_pts=pts;
  589. first_wdir = resize_wdir;
  590. }
  591. } else {
  592. // add either intersection_quad or pie_shape, based on corner_fill_arc option
  593. // for convex corner (convexity depends on sign of resizing, whether we shrink or grow)
  594. std::vector< std::vector<point_data<T> > > pts;
  595. direction_1d winding;
  596. winding = convex?COUNTERCLOCKWISE:CLOCKWISE;
  597. if (make_resizing_vertex_list(pts, curr_prev, prev_concave, *first, *second, *third, resizing
  598. , num_circle_segments, corner_fill_arc))
  599. {
  600. if (first_pts.size()) {
  601. for (int i=0; i<pts.size(); i++) {
  602. sizingSet.insert_vertex_sequence(pts[i].begin(),pts[i].end(),winding,false);
  603. }
  604. } else {
  605. first_pts = pts[0];
  606. first_wdir = resize_wdir;
  607. for (int i=1; i<pts.size(); i++) {
  608. sizingSet.insert_vertex_sequence(pts[i].begin(),pts[i].end(),winding,false);
  609. }
  610. }
  611. prev_point = curr_prev;
  612. } else {
  613. treat_as_concave = true;
  614. }
  615. }
  616. prev_concave = treat_as_concave;
  617. first = second;
  618. second = third;
  619. ++third;
  620. if(third == real_end) {
  621. third = begin_points(poly);
  622. if(*second == *third) {
  623. ++third; //skip first point if it is duplicate of last point
  624. }
  625. }
  626. } while(second != end);
  627. // handle insertion of first point
  628. if (!prev_concave) {
  629. first_pts[first_pts.size()-1]=prev_point;
  630. }
  631. sizingSet.insert_vertex_sequence(first_pts.begin(),first_pts.end(),first_wdir,false);
  632. polygon_set_data<coordinate_type> tmp;
  633. //insert original shape
  634. tmp.insert(poly, false, polygon_concept());
  635. if((resizing < 0) ^ hole) tmp -= sizingSet;
  636. else tmp += sizingSet;
  637. //tmp.clean();
  638. insert(tmp, hole);
  639. return (*this);
  640. }
  641. inline polygon_set_data&
  642. interact(const polygon_set_data& that);
  643. inline bool downcast(polygon_45_set_data<coordinate_type>& result) const {
  644. if(!is_45_) return false;
  645. for(iterator_type itr = begin(); itr != end(); ++itr) {
  646. const element_type& elem = *itr;
  647. int count = elem.second;
  648. int rise = 1; //up sloping 45
  649. if(scanline_base<coordinate_type>::is_horizontal(elem.first)) rise = 0;
  650. else if(scanline_base<coordinate_type>::is_vertical(elem.first)) rise = 2;
  651. else {
  652. if(!scanline_base<coordinate_type>::is_45_degree(elem.first)) {
  653. is_45_ = false;
  654. return false; //consider throwing because is_45_ has be be wrong
  655. }
  656. if(elem.first.first.y() > elem.first.second.y()) rise = -1; //down sloping 45
  657. }
  658. typename polygon_45_set_data<coordinate_type>::Vertex45Compact vertex(elem.first.first, rise, count);
  659. result.insert(vertex);
  660. typename polygon_45_set_data<coordinate_type>::Vertex45Compact vertex2(elem.first.second, rise, -count);
  661. result.insert(vertex2);
  662. }
  663. return true;
  664. }
  665. inline GEOMETRY_CONCEPT_ID concept_downcast() const {
  666. typedef typename coordinate_traits<coordinate_type>::coordinate_difference delta_type;
  667. bool is_45 = false;
  668. for(iterator_type itr = begin(); itr != end(); ++itr) {
  669. const element_type& elem = *itr;
  670. delta_type h_delta = euclidean_distance(elem.first.first, elem.first.second, HORIZONTAL);
  671. delta_type v_delta = euclidean_distance(elem.first.first, elem.first.second, VERTICAL);
  672. if(h_delta != 0 || v_delta != 0) {
  673. //neither delta is zero and the edge is not MANHATTAN
  674. if(v_delta != h_delta && v_delta != -h_delta) return POLYGON_SET_CONCEPT;
  675. else is_45 = true;
  676. }
  677. }
  678. if(is_45) return POLYGON_45_SET_CONCEPT;
  679. return POLYGON_90_SET_CONCEPT;
  680. }
  681. private:
  682. mutable value_type data_;
  683. mutable bool dirty_;
  684. mutable bool unsorted_;
  685. mutable bool is_45_;
  686. private:
  687. //functions
  688. template <typename output_container>
  689. void get_dispatch(output_container& output, polygon_concept tag) const {
  690. get_fracture(output, true, tag);
  691. }
  692. template <typename output_container>
  693. void get_dispatch(output_container& output, polygon_with_holes_concept tag) const {
  694. get_fracture(output, false, tag);
  695. }
  696. template <typename output_container, typename concept_type>
  697. void get_fracture(output_container& container, bool fracture_holes, concept_type ) const {
  698. clean();
  699. polygon_arbitrary_formation<coordinate_type> pf(fracture_holes);
  700. typedef typename polygon_arbitrary_formation<coordinate_type>::vertex_half_edge vertex_half_edge;
  701. std::vector<vertex_half_edge> data;
  702. for(iterator_type itr = data_.begin(); itr != data_.end(); ++itr){
  703. data.push_back(vertex_half_edge((*itr).first.first, (*itr).first.second, (*itr).second));
  704. data.push_back(vertex_half_edge((*itr).first.second, (*itr).first.first, -1 * (*itr).second));
  705. }
  706. polygon_sort(data.begin(), data.end());
  707. pf.scan(container, data.begin(), data.end());
  708. }
  709. };
  710. struct polygon_set_concept;
  711. template <typename T>
  712. struct geometry_concept<polygon_set_data<T> > {
  713. typedef polygon_set_concept type;
  714. };
  715. // template <typename T>
  716. // inline double compute_area(point_data<T>& a, point_data<T>& b, point_data<T>& c) {
  717. // return (double)(b.x()-a.x())*(double)(c.y()-a.y())- (double)(c.x()-a.x())*(double)(b.y()-a.y());
  718. // }
  719. template <typename T>
  720. inline int make_resizing_vertex_list(std::vector<std::vector<point_data< T> > >& return_points,
  721. point_data<T>& curr_prev, bool ignore_prev_point,
  722. point_data< T> start, point_data<T> middle, point_data< T> end,
  723. double sizing_distance, unsigned int num_circle_segments, bool corner_fill_arc) {
  724. // handle the case of adding an intersection point
  725. point_data<double> dn1( middle.y()-start.y(), start.x()-middle.x());
  726. double size = sizing_distance/std::sqrt( dn1.x()*dn1.x()+dn1.y()*dn1.y());
  727. dn1 = point_data<double>( dn1.x()*size, dn1.y()* size);
  728. point_data<double> dn2( end.y()-middle.y(), middle.x()-end.x());
  729. size = sizing_distance/std::sqrt( dn2.x()*dn2.x()+dn2.y()*dn2.y());
  730. dn2 = point_data<double>( dn2.x()*size, dn2.y()* size);
  731. point_data<double> start_offset((start.x()+dn1.x()),(start.y()+dn1.y()));
  732. point_data<double> mid1_offset((middle.x()+dn1.x()),(middle.y()+dn1.y()));
  733. point_data<double> end_offset((end.x()+dn2.x()),(end.y()+dn2.y()));
  734. point_data<double> mid2_offset((middle.x()+dn2.x()),(middle.y()+dn2.y()));
  735. if (ignore_prev_point)
  736. curr_prev = round_down<T>(start_offset);
  737. if (corner_fill_arc) {
  738. std::vector<point_data< T> > return_points1;
  739. return_points.push_back(return_points1);
  740. std::vector<point_data< T> >& return_points_back = return_points[return_points.size()-1];
  741. return_points_back.push_back(round_down<T>(mid1_offset));
  742. return_points_back.push_back(middle);
  743. return_points_back.push_back(start);
  744. return_points_back.push_back(curr_prev);
  745. point_data<double> dmid(middle.x(),middle.y());
  746. return_points.push_back(return_points1);
  747. int num = make_arc(return_points[return_points.size()-1],mid1_offset,mid2_offset,dmid,sizing_distance,num_circle_segments);
  748. curr_prev = round_down<T>(mid2_offset);
  749. return num;
  750. }
  751. std::pair<point_data<double>,point_data<double> > he1(start_offset,mid1_offset);
  752. std::pair<point_data<double>,point_data<double> > he2(mid2_offset ,end_offset);
  753. //typedef typename high_precision_type<double>::type high_precision;
  754. point_data<T> intersect;
  755. typename scanline_base<T>::compute_intersection_pack pack;
  756. bool res = pack.compute_intersection(intersect,he1,he2,true);
  757. if( res ) {
  758. std::vector<point_data< T> > return_points1;
  759. return_points.push_back(return_points1);
  760. std::vector<point_data< T> >& return_points_back = return_points[return_points.size()-1];
  761. return_points_back.push_back(intersect);
  762. return_points_back.push_back(middle);
  763. return_points_back.push_back(start);
  764. return_points_back.push_back(curr_prev);
  765. //double d1= compute_area(intersect,middle,start);
  766. //double d2= compute_area(start,curr_prev,intersect);
  767. curr_prev = intersect;
  768. return return_points.size();
  769. }
  770. return 0;
  771. }
  772. // this routine should take in start and end point s.t. end point is CCW from start
  773. // it sould make a pie slice polygon that is an intersection of that arc
  774. // with an ngon segments approximation of the circle centered at center with radius r
  775. // point start is gauaranteed to be on the segmentation
  776. // returnPoints will start with the first point after start
  777. // returnPoints vector may be empty
  778. template <typename T>
  779. inline int make_arc(std::vector<point_data< T> >& return_points,
  780. point_data< double> start, point_data< double> end,
  781. point_data< double> center, double r, unsigned int num_circle_segments) {
  782. const double our_pi=3.1415926535897932384626433832795028841971;
  783. // derive start and end angles
  784. double ps = atan2(start.y()-center.y(), start.x()-center.x());
  785. double pe = atan2(end.y()-center.y(), end.x()-center.x());
  786. if (ps < 0.0)
  787. ps += 2.0 * our_pi;
  788. if (pe <= 0.0)
  789. pe += 2.0 * our_pi;
  790. if (ps >= 2.0 * our_pi)
  791. ps -= 2.0 * our_pi;
  792. while (pe <= ps)
  793. pe += 2.0 * our_pi;
  794. double delta_angle = (2.0 * our_pi) / (double)num_circle_segments;
  795. if ( start==end) // full circle?
  796. {
  797. ps = delta_angle*0.5;
  798. pe = ps + our_pi * 2.0;
  799. double x,y;
  800. x = center.x() + r * cos(ps);
  801. y = center.y() + r * sin(ps);
  802. start = point_data<double>(x,y);
  803. end = start;
  804. }
  805. return_points.push_back(round_down<T>(center));
  806. return_points.push_back(round_down<T>(start));
  807. unsigned int i=0;
  808. double curr_angle = ps+delta_angle;
  809. while( curr_angle < pe - 0.01 && i < 2 * num_circle_segments) {
  810. i++;
  811. double x = center.x() + r * cos( curr_angle);
  812. double y = center.y() + r * sin( curr_angle);
  813. return_points.push_back( round_down<T>((point_data<double>(x,y))));
  814. curr_angle+=delta_angle;
  815. }
  816. return_points.push_back(round_down<T>(end));
  817. return return_points.size();
  818. }
  819. }// close namespace
  820. }// close name space
  821. #include "detail/scan_arbitrary.hpp"
  822. namespace boost { namespace polygon {
  823. //ConnectivityExtraction computes the graph of connectivity between rectangle, polygon and
  824. //polygon set graph nodes where an edge is created whenever the geometry in two nodes overlap
  825. template <typename coordinate_type>
  826. class connectivity_extraction{
  827. private:
  828. typedef arbitrary_connectivity_extraction<coordinate_type, int> ce;
  829. ce ce_;
  830. unsigned int nodeCount_;
  831. public:
  832. inline connectivity_extraction() : ce_(), nodeCount_(0) {}
  833. inline connectivity_extraction(const connectivity_extraction& that) : ce_(that.ce_),
  834. nodeCount_(that.nodeCount_) {}
  835. inline connectivity_extraction& operator=(const connectivity_extraction& that) {
  836. ce_ = that.ce_;
  837. nodeCount_ = that.nodeCount_; {}
  838. return *this;
  839. }
  840. //insert a polygon set graph node, the value returned is the id of the graph node
  841. inline unsigned int insert(const polygon_set_data<coordinate_type>& ps) {
  842. ps.clean();
  843. ce_.populateTouchSetData(ps.begin(), ps.end(), nodeCount_);
  844. return nodeCount_++;
  845. }
  846. template <class GeoObjT>
  847. inline unsigned int insert(const GeoObjT& geoObj) {
  848. polygon_set_data<coordinate_type> ps;
  849. ps.insert(geoObj);
  850. return insert(ps);
  851. }
  852. //extract connectivity and store the edges in the graph
  853. //graph must be indexable by graph node id and the indexed value must be a std::set of
  854. //graph node id
  855. template <class GraphT>
  856. inline void extract(GraphT& graph) {
  857. ce_.execute(graph);
  858. }
  859. };
  860. template <typename T>
  861. polygon_set_data<T>&
  862. polygon_set_data<T>::interact(const polygon_set_data<T>& that) {
  863. connectivity_extraction<coordinate_type> ce;
  864. std::vector<polygon_with_holes_data<T> > polys;
  865. get(polys);
  866. clear();
  867. for(std::size_t i = 0; i < polys.size(); ++i) {
  868. ce.insert(polys[i]);
  869. }
  870. int id = ce.insert(that);
  871. std::vector<std::set<int> > graph(id+1);
  872. ce.extract(graph);
  873. for(std::set<int>::iterator itr = graph[id].begin();
  874. itr != graph[id].end(); ++itr) {
  875. insert(polys[*itr]);
  876. }
  877. return *this;
  878. }
  879. }
  880. }
  881. #include "polygon_set_traits.hpp"
  882. #include "detail/polygon_set_view.hpp"
  883. #include "polygon_set_concept.hpp"
  884. #include "detail/minkowski.hpp"
  885. #endif