polygon_set_data.hpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  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. if (begin_vertex == end_vertex) {
  168. // No edges to insert.
  169. return;
  170. }
  171. // Current edge endpoints.
  172. iT vertex0 = begin_vertex;
  173. iT vertex1 = begin_vertex;
  174. if (++vertex1 == end_vertex) {
  175. // No edges to insert.
  176. return;
  177. }
  178. int wmultiplier = (winding == COUNTERCLOCKWISE) ? 1 : -1;
  179. if (is_hole) {
  180. wmultiplier = -wmultiplier;
  181. }
  182. dirty_ = true;
  183. unsorted_ = true;
  184. while (vertex0 != end_vertex) {
  185. point_type p0, p1;
  186. assign(p0, *vertex0);
  187. assign(p1, *vertex1);
  188. if (p0 != p1) {
  189. int hmultiplier = (p0.get(HORIZONTAL) == p1.get(HORIZONTAL)) ? -1 : 1;
  190. element_type elem(edge_type(p0, p1), hmultiplier * wmultiplier);
  191. insert_clean(elem);
  192. }
  193. ++vertex0;
  194. ++vertex1;
  195. if (vertex1 == end_vertex) {
  196. vertex1 = begin_vertex;
  197. }
  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. polygon_sort(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. // inequivalence operator
  239. inline bool operator!=(const polygon_set_data& p) const {
  240. return !((*this) == p);
  241. }
  242. // get iterator to begin vertex data
  243. inline iterator_type begin() const {
  244. return data_.begin();
  245. }
  246. // get iterator to end vertex data
  247. inline iterator_type end() const {
  248. return data_.end();
  249. }
  250. const value_type& value() const {
  251. return data_;
  252. }
  253. // clear the contents of the polygon_set_data
  254. inline void clear() { data_.clear(); dirty_ = unsorted_ = false; }
  255. // find out if Polygon set is empty
  256. inline bool empty() const { return data_.empty(); }
  257. // get the Polygon set size in vertices
  258. inline std::size_t size() const { clean(); return data_.size(); }
  259. // get the current Polygon set capacity in vertices
  260. inline std::size_t capacity() const { return data_.capacity(); }
  261. // reserve size of polygon set in vertices
  262. inline void reserve(std::size_t size) { return data_.reserve(size); }
  263. // find out if Polygon set is sorted
  264. inline bool sorted() const { return !unsorted_; }
  265. // find out if Polygon set is clean
  266. inline bool dirty() const { return dirty_; }
  267. void clean() const;
  268. void sort() const{
  269. if(unsorted_) {
  270. polygon_sort(data_.begin(), data_.end());
  271. unsorted_ = false;
  272. }
  273. }
  274. template <typename input_iterator_type>
  275. void set(input_iterator_type input_begin, input_iterator_type input_end) {
  276. clear();
  277. reserve(std::distance(input_begin,input_end));
  278. insert(input_begin, input_end);
  279. dirty_ = true;
  280. unsorted_ = true;
  281. }
  282. void set(const value_type& value) {
  283. data_ = value;
  284. dirty_ = true;
  285. unsorted_ = true;
  286. }
  287. template <typename rectangle_type>
  288. bool extents(rectangle_type& rect) {
  289. clean();
  290. if(empty()) return false;
  291. bool first_iteration = true;
  292. for(iterator_type itr = begin();
  293. itr != end(); ++itr) {
  294. rectangle_type edge_box;
  295. set_points(edge_box, (*itr).first.first, (*itr).first.second);
  296. if(first_iteration)
  297. rect = edge_box;
  298. else
  299. encompass(rect, edge_box);
  300. first_iteration = false;
  301. }
  302. return true;
  303. }
  304. inline polygon_set_data&
  305. resize(coordinate_type resizing, bool corner_fill_arc = false, unsigned int num_circle_segments=0);
  306. template <typename transform_type>
  307. inline polygon_set_data&
  308. transform(const transform_type& tr) {
  309. std::vector<polygon_with_holes_data<T> > polys;
  310. get(polys);
  311. clear();
  312. for(std::size_t i = 0 ; i < polys.size(); ++i) {
  313. ::boost::polygon::transform(polys[i], tr);
  314. insert(polys[i]);
  315. }
  316. unsorted_ = true;
  317. dirty_ = true;
  318. return *this;
  319. }
  320. inline polygon_set_data&
  321. scale_up(typename coordinate_traits<coordinate_type>::unsigned_area_type factor) {
  322. for(typename value_type::iterator itr = data_.begin(); itr != data_.end(); ++itr) {
  323. ::boost::polygon::scale_up((*itr).first.first, factor);
  324. ::boost::polygon::scale_up((*itr).first.second, factor);
  325. }
  326. return *this;
  327. }
  328. inline polygon_set_data&
  329. scale_down(typename coordinate_traits<coordinate_type>::unsigned_area_type factor) {
  330. for(typename value_type::iterator itr = data_.begin(); itr != data_.end(); ++itr) {
  331. bool vb = (*itr).first.first.x() == (*itr).first.second.x();
  332. ::boost::polygon::scale_down((*itr).first.first, factor);
  333. ::boost::polygon::scale_down((*itr).first.second, factor);
  334. bool va = (*itr).first.first.x() == (*itr).first.second.x();
  335. if(!vb && va) {
  336. (*itr).second *= -1;
  337. }
  338. }
  339. unsorted_ = true;
  340. dirty_ = true;
  341. return *this;
  342. }
  343. template <typename scaling_type>
  344. inline polygon_set_data& scale(polygon_set_data&,
  345. const scaling_type& scaling) {
  346. for(typename value_type::iterator itr = begin(); itr != end(); ++itr) {
  347. bool vb = (*itr).first.first.x() == (*itr).first.second.x();
  348. ::boost::polygon::scale((*itr).first.first, scaling);
  349. ::boost::polygon::scale((*itr).first.second, scaling);
  350. bool va = (*itr).first.first.x() == (*itr).first.second.x();
  351. if(!vb && va) {
  352. (*itr).second *= -1;
  353. }
  354. }
  355. unsorted_ = true;
  356. dirty_ = true;
  357. return *this;
  358. }
  359. static inline void compute_offset_edge(point_data<long double>& pt1, point_data<long double>& pt2,
  360. const point_data<long double>& prev_pt,
  361. const point_data<long double>& current_pt,
  362. long double distance, int multiplier) {
  363. long double dx = current_pt.x() - prev_pt.x();
  364. long double dy = current_pt.y() - prev_pt.y();
  365. long double edge_length = std::sqrt(dx*dx + dy*dy);
  366. long double dnx = dy;
  367. long double dny = -dx;
  368. dnx = dnx * (long double)distance / edge_length;
  369. dny = dny * (long double)distance / edge_length;
  370. pt1.x(prev_pt.x() + (long double)dnx * (long double)multiplier);
  371. pt2.x(current_pt.x() + (long double)dnx * (long double)multiplier);
  372. pt1.y(prev_pt.y() + (long double)dny * (long double)multiplier);
  373. pt2.y(current_pt.y() + (long double)dny * (long double)multiplier);
  374. }
  375. static inline void modify_pt(point_data<coordinate_type>& pt, const point_data<coordinate_type>& prev_pt,
  376. const point_data<coordinate_type>& current_pt, const point_data<coordinate_type>& next_pt,
  377. coordinate_type distance, coordinate_type multiplier) {
  378. std::pair<point_data<long double>, point_data<long double> > he1, he2;
  379. he1.first.x((long double)(prev_pt.x()));
  380. he1.first.y((long double)(prev_pt.y()));
  381. he1.second.x((long double)(current_pt.x()));
  382. he1.second.y((long double)(current_pt.y()));
  383. he2.first.x((long double)(current_pt.x()));
  384. he2.first.y((long double)(current_pt.y()));
  385. he2.second.x((long double)(next_pt.x()));
  386. he2.second.y((long double)(next_pt.y()));
  387. compute_offset_edge(he1.first, he1.second, prev_pt, current_pt, distance, multiplier);
  388. compute_offset_edge(he2.first, he2.second, current_pt, next_pt, distance, multiplier);
  389. typedef scanline_base<long double>::compute_intersection_pack pack;
  390. point_data<long double> rpt;
  391. point_data<long double> bisectorpt((he1.second.x()+he2.first.x())/2,
  392. (he1.second.y()+he2.first.y())/2);
  393. point_data<long double> orig_pt((long double)pt.x(), (long double)pt.y());
  394. if(euclidean_distance(bisectorpt, orig_pt) < distance/2) {
  395. if(!pack::compute_lazy_intersection(rpt, he1, he2, true, false)) {
  396. rpt = he1.second; //colinear offset edges use shared point
  397. }
  398. } else {
  399. if(!pack::compute_lazy_intersection(rpt, he1, std::pair<point_data<long double>, point_data<long double> >(orig_pt, bisectorpt), true, false)) {
  400. rpt = he1.second; //colinear offset edges use shared point
  401. }
  402. }
  403. pt.x((coordinate_type)(std::floor(rpt.x()+0.5)));
  404. pt.y((coordinate_type)(std::floor(rpt.y()+0.5)));
  405. }
  406. static void resize_poly_up(std::vector<point_data<coordinate_type> >& poly, coordinate_type distance, coordinate_type multiplier) {
  407. point_data<coordinate_type> first_pt = poly[0];
  408. point_data<coordinate_type> second_pt = poly[1];
  409. point_data<coordinate_type> prev_pt = poly[0];
  410. point_data<coordinate_type> current_pt = poly[1];
  411. for(std::size_t i = 2; i < poly.size()-1; ++i) {
  412. point_data<coordinate_type> next_pt = poly[i];
  413. modify_pt(poly[i-1], prev_pt, current_pt, next_pt, distance, multiplier);
  414. prev_pt = current_pt;
  415. current_pt = next_pt;
  416. }
  417. point_data<coordinate_type> next_pt = first_pt;
  418. modify_pt(poly[poly.size()-2], prev_pt, current_pt, next_pt, distance, multiplier);
  419. prev_pt = current_pt;
  420. current_pt = next_pt;
  421. next_pt = second_pt;
  422. modify_pt(poly[0], prev_pt, current_pt, next_pt, distance, multiplier);
  423. poly.back() = poly.front();
  424. }
  425. static bool resize_poly_down(std::vector<point_data<coordinate_type> >& poly, coordinate_type distance, coordinate_type multiplier) {
  426. std::vector<point_data<coordinate_type> > orig_poly(poly);
  427. rectangle_data<coordinate_type> extents_rectangle;
  428. set_points(extents_rectangle, poly[0], poly[0]);
  429. point_data<coordinate_type> first_pt = poly[0];
  430. point_data<coordinate_type> second_pt = poly[1];
  431. point_data<coordinate_type> prev_pt = poly[0];
  432. point_data<coordinate_type> current_pt = poly[1];
  433. encompass(extents_rectangle, current_pt);
  434. for(std::size_t i = 2; i < poly.size()-1; ++i) {
  435. point_data<coordinate_type> next_pt = poly[i];
  436. encompass(extents_rectangle, next_pt);
  437. modify_pt(poly[i-1], prev_pt, current_pt, next_pt, distance, multiplier);
  438. prev_pt = current_pt;
  439. current_pt = next_pt;
  440. }
  441. if(delta(extents_rectangle, HORIZONTAL) <= std::abs(2*distance))
  442. return false;
  443. if(delta(extents_rectangle, VERTICAL) <= std::abs(2*distance))
  444. return false;
  445. point_data<coordinate_type> next_pt = first_pt;
  446. modify_pt(poly[poly.size()-2], prev_pt, current_pt, next_pt, distance, multiplier);
  447. prev_pt = current_pt;
  448. current_pt = next_pt;
  449. next_pt = second_pt;
  450. modify_pt(poly[0], prev_pt, current_pt, next_pt, distance, multiplier);
  451. poly.back() = poly.front();
  452. //if the line segments formed between orignial and new points cross for an edge that edge inverts
  453. //if all edges invert the polygon should be discarded
  454. //if even one edge does not invert return true because the polygon is valid
  455. bool non_inverting_edge = false;
  456. for(std::size_t i = 1; i < poly.size(); ++i) {
  457. std::pair<point_data<coordinate_type>, point_data<coordinate_type> >
  458. he1(poly[i], orig_poly[i]),
  459. he2(poly[i-1], orig_poly[i-1]);
  460. if(!scanline_base<coordinate_type>::intersects(he1, he2)) {
  461. non_inverting_edge = true;
  462. break;
  463. }
  464. }
  465. return non_inverting_edge;
  466. }
  467. polygon_set_data&
  468. bloat(typename coordinate_traits<coordinate_type>::unsigned_area_type distance) {
  469. std::list<polygon_with_holes_data<coordinate_type> > polys;
  470. get(polys);
  471. clear();
  472. for(typename std::list<polygon_with_holes_data<coordinate_type> >::iterator itr = polys.begin();
  473. itr != polys.end(); ++itr) {
  474. resize_poly_up((*itr).self_.coords_, (coordinate_type)distance, (coordinate_type)1);
  475. insert_vertex_sequence((*itr).self_.begin(), (*itr).self_.end(), COUNTERCLOCKWISE, false); //inserts without holes
  476. for(typename std::list<polygon_data<coordinate_type> >::iterator itrh = (*itr).holes_.begin();
  477. itrh != (*itr).holes_.end(); ++itrh) {
  478. if(resize_poly_down((*itrh).coords_, (coordinate_type)distance, (coordinate_type)1)) {
  479. insert_vertex_sequence((*itrh).coords_.begin(), (*itrh).coords_.end(), CLOCKWISE, true);
  480. }
  481. }
  482. }
  483. return *this;
  484. }
  485. polygon_set_data&
  486. shrink(typename coordinate_traits<coordinate_type>::unsigned_area_type distance) {
  487. std::list<polygon_with_holes_data<coordinate_type> > polys;
  488. get(polys);
  489. clear();
  490. for(typename std::list<polygon_with_holes_data<coordinate_type> >::iterator itr = polys.begin();
  491. itr != polys.end(); ++itr) {
  492. if(resize_poly_down((*itr).self_.coords_, (coordinate_type)distance, (coordinate_type)-1)) {
  493. insert_vertex_sequence((*itr).self_.begin(), (*itr).self_.end(), COUNTERCLOCKWISE, false); //inserts without holes
  494. for(typename std::list<polygon_data<coordinate_type> >::iterator itrh = (*itr).holes_.begin();
  495. itrh != (*itr).holes_.end(); ++itrh) {
  496. resize_poly_up((*itrh).coords_, (coordinate_type)distance, (coordinate_type)-1);
  497. insert_vertex_sequence((*itrh).coords_.begin(), (*itrh).coords_.end(), CLOCKWISE, true);
  498. }
  499. }
  500. }
  501. return *this;
  502. }
  503. // TODO:: should be private
  504. template <typename geometry_type>
  505. inline polygon_set_data&
  506. insert_with_resize(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc=false, unsigned int num_circle_segments=0, bool hole = false) {
  507. return insert_with_resize_dispatch(poly, resizing, corner_fill_arc, num_circle_segments, hole, typename geometry_concept<geometry_type>::type());
  508. }
  509. template <typename geometry_type>
  510. inline polygon_set_data&
  511. insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole,
  512. polygon_with_holes_concept) {
  513. insert_with_resize_dispatch(poly, resizing, corner_fill_arc, num_circle_segments, hole, polygon_concept());
  514. for(typename polygon_with_holes_traits<geometry_type>::iterator_holes_type itr =
  515. begin_holes(poly); itr != end_holes(poly);
  516. ++itr) {
  517. insert_with_resize_dispatch(*itr, resizing, corner_fill_arc, num_circle_segments, !hole, polygon_concept());
  518. }
  519. return *this;
  520. }
  521. template <typename geometry_type>
  522. inline polygon_set_data&
  523. insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole,
  524. polygon_concept) {
  525. if (resizing==0)
  526. return *this;
  527. // one dimensional used to store CCW/CW flag
  528. //direction_1d wdir = winding(poly);
  529. // LOW==CLOCKWISE just faster to type
  530. // so > 0 is CCW
  531. //int multiplier = wdir == LOW ? -1 : 1;
  532. //std::cout<<" multiplier : "<<multiplier<<std::endl;
  533. //if(hole) resizing *= -1;
  534. direction_1d resize_wdir = resizing>0?COUNTERCLOCKWISE:CLOCKWISE;
  535. typedef typename polygon_data<T>::iterator_type piterator;
  536. piterator first, second, third, end, real_end;
  537. real_end = end_points(poly);
  538. third = begin_points(poly);
  539. first = third;
  540. if(first == real_end) return *this;
  541. ++third;
  542. if(third == real_end) return *this;
  543. second = end = third;
  544. ++third;
  545. if(third == real_end) return *this;
  546. // for 1st corner
  547. std::vector<point_data<T> > first_pts;
  548. std::vector<point_data<T> > all_pts;
  549. direction_1d first_wdir = CLOCKWISE;
  550. // for all corners
  551. polygon_set_data<T> sizingSet;
  552. bool sizing_sign = resizing<0;
  553. bool prev_concave = true;
  554. point_data<T> prev_point;
  555. //int iCtr=0;
  556. //insert minkofski shapes on edges and corners
  557. do { // REAL WORK IS HERE
  558. //first, second and third point to points in correct CCW order
  559. // check if convex or concave case
  560. point_data<coordinate_type> normal1( second->y()-first->y(), first->x()-second->x());
  561. point_data<coordinate_type> normal2( third->y()-second->y(), second->x()-third->x());
  562. double direction = normal1.x()*normal2.y()- normal2.x()*normal1.y();
  563. bool convex = direction>0;
  564. bool treat_as_concave = !convex;
  565. if(sizing_sign)
  566. treat_as_concave = convex;
  567. point_data<double> v;
  568. assign(v, normal1);
  569. double s2 = (v.x()*v.x()+v.y()*v.y());
  570. double s = std::sqrt(s2)/resizing;
  571. v = point_data<double>(v.x()/s,v.y()/s);
  572. point_data<T> curr_prev;
  573. if (prev_concave)
  574. //TODO missing round_down()
  575. curr_prev = point_data<T>(first->x()+v.x(),first->y()+v.y());
  576. else
  577. curr_prev = prev_point;
  578. // around concave corners - insert rectangle
  579. // if previous corner is concave it's point info may be ignored
  580. if ( treat_as_concave) {
  581. std::vector<point_data<T> > pts;
  582. pts.push_back(point_data<T>(second->x()+v.x(),second->y()+v.y()));
  583. pts.push_back(*second);
  584. pts.push_back(*first);
  585. pts.push_back(point_data<T>(curr_prev));
  586. if (first_pts.size()){
  587. sizingSet.insert_vertex_sequence(pts.begin(),pts.end(), resize_wdir,false);
  588. }else {
  589. first_pts=pts;
  590. first_wdir = resize_wdir;
  591. }
  592. } else {
  593. // add either intersection_quad or pie_shape, based on corner_fill_arc option
  594. // for convex corner (convexity depends on sign of resizing, whether we shrink or grow)
  595. std::vector< std::vector<point_data<T> > > pts;
  596. direction_1d winding;
  597. winding = convex?COUNTERCLOCKWISE:CLOCKWISE;
  598. if (make_resizing_vertex_list(pts, curr_prev, prev_concave, *first, *second, *third, resizing
  599. , num_circle_segments, corner_fill_arc))
  600. {
  601. if (first_pts.size()) {
  602. for (int i=0; i<pts.size(); i++) {
  603. sizingSet.insert_vertex_sequence(pts[i].begin(),pts[i].end(),winding,false);
  604. }
  605. } else {
  606. first_pts = pts[0];
  607. first_wdir = resize_wdir;
  608. for (int i=1; i<pts.size(); i++) {
  609. sizingSet.insert_vertex_sequence(pts[i].begin(),pts[i].end(),winding,false);
  610. }
  611. }
  612. prev_point = curr_prev;
  613. } else {
  614. treat_as_concave = true;
  615. }
  616. }
  617. prev_concave = treat_as_concave;
  618. first = second;
  619. second = third;
  620. ++third;
  621. if(third == real_end) {
  622. third = begin_points(poly);
  623. if(*second == *third) {
  624. ++third; //skip first point if it is duplicate of last point
  625. }
  626. }
  627. } while(second != end);
  628. // handle insertion of first point
  629. if (!prev_concave) {
  630. first_pts[first_pts.size()-1]=prev_point;
  631. }
  632. sizingSet.insert_vertex_sequence(first_pts.begin(),first_pts.end(),first_wdir,false);
  633. polygon_set_data<coordinate_type> tmp;
  634. //insert original shape
  635. tmp.insert(poly, false, polygon_concept());
  636. if((resizing < 0) ^ hole) tmp -= sizingSet;
  637. else tmp += sizingSet;
  638. //tmp.clean();
  639. insert(tmp, hole);
  640. return (*this);
  641. }
  642. inline polygon_set_data&
  643. interact(const polygon_set_data& that);
  644. inline bool downcast(polygon_45_set_data<coordinate_type>& result) const {
  645. if(!is_45_) return false;
  646. for(iterator_type itr = begin(); itr != end(); ++itr) {
  647. const element_type& elem = *itr;
  648. int count = elem.second;
  649. int rise = 1; //up sloping 45
  650. if(scanline_base<coordinate_type>::is_horizontal(elem.first)) rise = 0;
  651. else if(scanline_base<coordinate_type>::is_vertical(elem.first)) rise = 2;
  652. else {
  653. if(!scanline_base<coordinate_type>::is_45_degree(elem.first)) {
  654. is_45_ = false;
  655. return false; //consider throwing because is_45_ has be be wrong
  656. }
  657. if(elem.first.first.y() > elem.first.second.y()) rise = -1; //down sloping 45
  658. }
  659. typename polygon_45_set_data<coordinate_type>::Vertex45Compact vertex(elem.first.first, rise, count);
  660. result.insert(vertex);
  661. typename polygon_45_set_data<coordinate_type>::Vertex45Compact vertex2(elem.first.second, rise, -count);
  662. result.insert(vertex2);
  663. }
  664. return true;
  665. }
  666. inline GEOMETRY_CONCEPT_ID concept_downcast() const {
  667. typedef typename coordinate_traits<coordinate_type>::coordinate_difference delta_type;
  668. bool is_45 = false;
  669. for(iterator_type itr = begin(); itr != end(); ++itr) {
  670. const element_type& elem = *itr;
  671. delta_type h_delta = euclidean_distance(elem.first.first, elem.first.second, HORIZONTAL);
  672. delta_type v_delta = euclidean_distance(elem.first.first, elem.first.second, VERTICAL);
  673. if(h_delta != 0 || v_delta != 0) {
  674. //neither delta is zero and the edge is not MANHATTAN
  675. if(v_delta != h_delta && v_delta != -h_delta) return POLYGON_SET_CONCEPT;
  676. else is_45 = true;
  677. }
  678. }
  679. if(is_45) return POLYGON_45_SET_CONCEPT;
  680. return POLYGON_90_SET_CONCEPT;
  681. }
  682. private:
  683. mutable value_type data_;
  684. mutable bool dirty_;
  685. mutable bool unsorted_;
  686. mutable bool is_45_;
  687. private:
  688. //functions
  689. template <typename output_container>
  690. void get_dispatch(output_container& output, polygon_concept tag) const {
  691. get_fracture(output, true, tag);
  692. }
  693. template <typename output_container>
  694. void get_dispatch(output_container& output, polygon_with_holes_concept tag) const {
  695. get_fracture(output, false, tag);
  696. }
  697. template <typename output_container, typename concept_type>
  698. void get_fracture(output_container& container, bool fracture_holes, concept_type ) const {
  699. clean();
  700. polygon_arbitrary_formation<coordinate_type> pf(fracture_holes);
  701. typedef typename polygon_arbitrary_formation<coordinate_type>::vertex_half_edge vertex_half_edge;
  702. std::vector<vertex_half_edge> data;
  703. for(iterator_type itr = data_.begin(); itr != data_.end(); ++itr){
  704. data.push_back(vertex_half_edge((*itr).first.first, (*itr).first.second, (*itr).second));
  705. data.push_back(vertex_half_edge((*itr).first.second, (*itr).first.first, -1 * (*itr).second));
  706. }
  707. polygon_sort(data.begin(), data.end());
  708. pf.scan(container, data.begin(), data.end());
  709. }
  710. };
  711. struct polygon_set_concept;
  712. template <typename T>
  713. struct geometry_concept<polygon_set_data<T> > {
  714. typedef polygon_set_concept type;
  715. };
  716. // template <typename T>
  717. // inline double compute_area(point_data<T>& a, point_data<T>& b, point_data<T>& c) {
  718. // return (double)(b.x()-a.x())*(double)(c.y()-a.y())- (double)(c.x()-a.x())*(double)(b.y()-a.y());
  719. // }
  720. template <typename T>
  721. inline int make_resizing_vertex_list(std::vector<std::vector<point_data< T> > >& return_points,
  722. point_data<T>& curr_prev, bool ignore_prev_point,
  723. point_data< T> start, point_data<T> middle, point_data< T> end,
  724. double sizing_distance, unsigned int num_circle_segments, bool corner_fill_arc) {
  725. // handle the case of adding an intersection point
  726. point_data<double> dn1( middle.y()-start.y(), start.x()-middle.x());
  727. double size = sizing_distance/std::sqrt( dn1.x()*dn1.x()+dn1.y()*dn1.y());
  728. dn1 = point_data<double>( dn1.x()*size, dn1.y()* size);
  729. point_data<double> dn2( end.y()-middle.y(), middle.x()-end.x());
  730. size = sizing_distance/std::sqrt( dn2.x()*dn2.x()+dn2.y()*dn2.y());
  731. dn2 = point_data<double>( dn2.x()*size, dn2.y()* size);
  732. point_data<double> start_offset((start.x()+dn1.x()),(start.y()+dn1.y()));
  733. point_data<double> mid1_offset((middle.x()+dn1.x()),(middle.y()+dn1.y()));
  734. point_data<double> end_offset((end.x()+dn2.x()),(end.y()+dn2.y()));
  735. point_data<double> mid2_offset((middle.x()+dn2.x()),(middle.y()+dn2.y()));
  736. if (ignore_prev_point)
  737. curr_prev = round_down<T>(start_offset);
  738. if (corner_fill_arc) {
  739. std::vector<point_data< T> > return_points1;
  740. return_points.push_back(return_points1);
  741. std::vector<point_data< T> >& return_points_back = return_points[return_points.size()-1];
  742. return_points_back.push_back(round_down<T>(mid1_offset));
  743. return_points_back.push_back(middle);
  744. return_points_back.push_back(start);
  745. return_points_back.push_back(curr_prev);
  746. point_data<double> dmid(middle.x(),middle.y());
  747. return_points.push_back(return_points1);
  748. int num = make_arc(return_points[return_points.size()-1],mid1_offset,mid2_offset,dmid,sizing_distance,num_circle_segments);
  749. curr_prev = round_down<T>(mid2_offset);
  750. return num;
  751. }
  752. std::pair<point_data<double>,point_data<double> > he1(start_offset,mid1_offset);
  753. std::pair<point_data<double>,point_data<double> > he2(mid2_offset ,end_offset);
  754. //typedef typename high_precision_type<double>::type high_precision;
  755. point_data<T> intersect;
  756. typename scanline_base<T>::compute_intersection_pack pack;
  757. bool res = pack.compute_intersection(intersect,he1,he2,true);
  758. if( res ) {
  759. std::vector<point_data< T> > return_points1;
  760. return_points.push_back(return_points1);
  761. std::vector<point_data< T> >& return_points_back = return_points[return_points.size()-1];
  762. return_points_back.push_back(intersect);
  763. return_points_back.push_back(middle);
  764. return_points_back.push_back(start);
  765. return_points_back.push_back(curr_prev);
  766. //double d1= compute_area(intersect,middle,start);
  767. //double d2= compute_area(start,curr_prev,intersect);
  768. curr_prev = intersect;
  769. return return_points.size();
  770. }
  771. return 0;
  772. }
  773. // this routine should take in start and end point s.t. end point is CCW from start
  774. // it sould make a pie slice polygon that is an intersection of that arc
  775. // with an ngon segments approximation of the circle centered at center with radius r
  776. // point start is gauaranteed to be on the segmentation
  777. // returnPoints will start with the first point after start
  778. // returnPoints vector may be empty
  779. template <typename T>
  780. inline int make_arc(std::vector<point_data< T> >& return_points,
  781. point_data< double> start, point_data< double> end,
  782. point_data< double> center, double r, unsigned int num_circle_segments) {
  783. const double our_pi=3.1415926535897932384626433832795028841971;
  784. // derive start and end angles
  785. double ps = atan2(start.y()-center.y(), start.x()-center.x());
  786. double pe = atan2(end.y()-center.y(), end.x()-center.x());
  787. if (ps < 0.0)
  788. ps += 2.0 * our_pi;
  789. if (pe <= 0.0)
  790. pe += 2.0 * our_pi;
  791. if (ps >= 2.0 * our_pi)
  792. ps -= 2.0 * our_pi;
  793. while (pe <= ps)
  794. pe += 2.0 * our_pi;
  795. double delta_angle = (2.0 * our_pi) / (double)num_circle_segments;
  796. if ( start==end) // full circle?
  797. {
  798. ps = delta_angle*0.5;
  799. pe = ps + our_pi * 2.0;
  800. double x,y;
  801. x = center.x() + r * cos(ps);
  802. y = center.y() + r * sin(ps);
  803. start = point_data<double>(x,y);
  804. end = start;
  805. }
  806. return_points.push_back(round_down<T>(center));
  807. return_points.push_back(round_down<T>(start));
  808. unsigned int i=0;
  809. double curr_angle = ps+delta_angle;
  810. while( curr_angle < pe - 0.01 && i < 2 * num_circle_segments) {
  811. i++;
  812. double x = center.x() + r * cos( curr_angle);
  813. double y = center.y() + r * sin( curr_angle);
  814. return_points.push_back( round_down<T>((point_data<double>(x,y))));
  815. curr_angle+=delta_angle;
  816. }
  817. return_points.push_back(round_down<T>(end));
  818. return return_points.size();
  819. }
  820. }// close namespace
  821. }// close name space
  822. #include "detail/scan_arbitrary.hpp"
  823. namespace boost { namespace polygon {
  824. //ConnectivityExtraction computes the graph of connectivity between rectangle, polygon and
  825. //polygon set graph nodes where an edge is created whenever the geometry in two nodes overlap
  826. template <typename coordinate_type>
  827. class connectivity_extraction{
  828. private:
  829. typedef arbitrary_connectivity_extraction<coordinate_type, int> ce;
  830. ce ce_;
  831. unsigned int nodeCount_;
  832. public:
  833. inline connectivity_extraction() : ce_(), nodeCount_(0) {}
  834. inline connectivity_extraction(const connectivity_extraction& that) : ce_(that.ce_),
  835. nodeCount_(that.nodeCount_) {}
  836. inline connectivity_extraction& operator=(const connectivity_extraction& that) {
  837. ce_ = that.ce_;
  838. nodeCount_ = that.nodeCount_; {}
  839. return *this;
  840. }
  841. //insert a polygon set graph node, the value returned is the id of the graph node
  842. inline unsigned int insert(const polygon_set_data<coordinate_type>& ps) {
  843. ps.clean();
  844. ce_.populateTouchSetData(ps.begin(), ps.end(), nodeCount_);
  845. return nodeCount_++;
  846. }
  847. template <class GeoObjT>
  848. inline unsigned int insert(const GeoObjT& geoObj) {
  849. polygon_set_data<coordinate_type> ps;
  850. ps.insert(geoObj);
  851. return insert(ps);
  852. }
  853. //extract connectivity and store the edges in the graph
  854. //graph must be indexable by graph node id and the indexed value must be a std::set of
  855. //graph node id
  856. template <class GraphT>
  857. inline void extract(GraphT& graph) {
  858. ce_.execute(graph);
  859. }
  860. };
  861. template <typename T>
  862. polygon_set_data<T>&
  863. polygon_set_data<T>::interact(const polygon_set_data<T>& that) {
  864. connectivity_extraction<coordinate_type> ce;
  865. std::vector<polygon_with_holes_data<T> > polys;
  866. get(polys);
  867. clear();
  868. for(std::size_t i = 0; i < polys.size(); ++i) {
  869. ce.insert(polys[i]);
  870. }
  871. int id = ce.insert(that);
  872. std::vector<std::set<int> > graph(id+1);
  873. ce.extract(graph);
  874. for(std::set<int>::iterator itr = graph[id].begin();
  875. itr != graph[id].end(); ++itr) {
  876. insert(polys[*itr]);
  877. }
  878. return *this;
  879. }
  880. }
  881. }
  882. #include "polygon_set_traits.hpp"
  883. #include "detail/polygon_set_view.hpp"
  884. #include "polygon_set_concept.hpp"
  885. #include "detail/minkowski.hpp"
  886. #endif