/Src/Dependencies/Boost/boost/polygon/polygon_set_data.hpp

http://hadesmem.googlecode.com/ · C++ Header · 1000 lines · 798 code · 120 blank · 82 comment · 141 complexity · 0cf55e167595830101eb2f2c7ceade9a MD5 · raw file

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