rectangle_formation.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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_RECTANGLE_FORMATION_HPP
  8. #define BOOST_POLYGON_RECTANGLE_FORMATION_HPP
  9. namespace boost { namespace polygon{
  10. namespace rectangle_formation {
  11. template <class T>
  12. class ScanLineToRects {
  13. public:
  14. typedef T rectangle_type;
  15. typedef typename rectangle_traits<T>::coordinate_type coordinate_type;
  16. typedef rectangle_data<coordinate_type> scan_rect_type;
  17. private:
  18. typedef std::set<scan_rect_type, less_rectangle_concept<scan_rect_type, scan_rect_type> > ScanData;
  19. ScanData scanData_;
  20. bool haveCurrentRect_;
  21. scan_rect_type currentRect_;
  22. orientation_2d orient_;
  23. typename rectangle_traits<T>::coordinate_type currentCoordinate_;
  24. public:
  25. inline ScanLineToRects() : scanData_(), haveCurrentRect_(), currentRect_(), orient_(), currentCoordinate_() {}
  26. inline ScanLineToRects(orientation_2d orient, rectangle_type model) :
  27. scanData_(orientation_2d(orient.to_int() ? VERTICAL : HORIZONTAL)),
  28. haveCurrentRect_(false), currentRect_(), orient_(orient), currentCoordinate_() {
  29. assign(currentRect_, model);
  30. currentCoordinate_ = (std::numeric_limits<coordinate_type>::max)();
  31. }
  32. template <typename CT>
  33. inline ScanLineToRects& processEdge(CT& rectangles, const interval_data<coordinate_type>& edge);
  34. inline ScanLineToRects& nextMajorCoordinate(coordinate_type currentCoordinate) {
  35. if(haveCurrentRect_) {
  36. scanData_.insert(scanData_.end(), currentRect_);
  37. haveCurrentRect_ = false;
  38. }
  39. currentCoordinate_ = currentCoordinate;
  40. return *this;
  41. }
  42. };
  43. template <class CT, class ST, class rectangle_type, typename interval_type, typename coordinate_type> inline CT&
  44. processEdge_(CT& rectangles, ST& scanData, const interval_type& edge,
  45. bool& haveCurrentRect, rectangle_type& currentRect, coordinate_type currentCoordinate, orientation_2d orient)
  46. {
  47. typedef typename CT::value_type result_type;
  48. bool edgeProcessed = false;
  49. if(!scanData.empty()) {
  50. //process all rectangles in the scanData that touch the edge
  51. typename ST::iterator dataIter = scanData.lower_bound(rectangle_type(edge, edge));
  52. //decrement beginIter until its low is less than edge's low
  53. while((dataIter == scanData.end() || (*dataIter).get(orient).get(LOW) > edge.get(LOW)) &&
  54. dataIter != scanData.begin())
  55. {
  56. --dataIter;
  57. }
  58. //process each rectangle until the low end of the rectangle
  59. //is greater than the high end of the edge
  60. while(dataIter != scanData.end() &&
  61. (*dataIter).get(orient).get(LOW) <= edge.get(HIGH))
  62. {
  63. const rectangle_type& rect = *dataIter;
  64. //if the rectangle data intersects the edge at all
  65. if(rect.get(orient).get(HIGH) >= edge.get(LOW)) {
  66. if(contains(rect.get(orient), edge, true)) {
  67. //this is a closing edge
  68. //we need to write out the intersecting rectangle and
  69. //insert between 0 and 2 rectangles into the scanData
  70. //write out rectangle
  71. rectangle_type tmpRect = rect;
  72. if(rect.get(orient.get_perpendicular()).get(LOW) < currentCoordinate) {
  73. //set the high coordinate perpedicular to slicing orientation
  74. //to the current coordinate of the scan event
  75. tmpRect.set(orient.get_perpendicular().get_direction(HIGH),
  76. currentCoordinate);
  77. result_type result;
  78. assign(result, tmpRect);
  79. rectangles.insert(rectangles.end(), result);
  80. }
  81. //erase the rectangle from the scan data
  82. typename ST::iterator nextIter = dataIter;
  83. ++nextIter;
  84. scanData.erase(dataIter);
  85. if(tmpRect.get(orient).get(LOW) < edge.get(LOW)) {
  86. //insert a rectangle for the overhang of the bottom
  87. //of the rectangle back into scan data
  88. rectangle_type lowRect(tmpRect);
  89. lowRect.set(orient.get_perpendicular(), interval_data<coordinate_type>(currentCoordinate,
  90. currentCoordinate));
  91. lowRect.set(orient.get_direction(HIGH), edge.get(LOW));
  92. scanData.insert(nextIter, lowRect);
  93. }
  94. if(tmpRect.get(orient).get(HIGH) > edge.get(HIGH)) {
  95. //insert a rectangle for the overhang of the top
  96. //of the rectangle back into scan data
  97. rectangle_type highRect(tmpRect);
  98. highRect.set(orient.get_perpendicular(), interval_data<coordinate_type>(currentCoordinate,
  99. currentCoordinate));
  100. highRect.set(orient.get_direction(LOW), edge.get(HIGH));
  101. scanData.insert(nextIter, highRect);
  102. }
  103. //we are done with this edge
  104. edgeProcessed = true;
  105. break;
  106. } else {
  107. //it must be an opening edge
  108. //assert that rect does not overlap the edge but only touches
  109. //write out rectangle
  110. rectangle_type tmpRect = rect;
  111. //set the high coordinate perpedicular to slicing orientation
  112. //to the current coordinate of the scan event
  113. if(tmpRect.get(orient.get_perpendicular().get_direction(LOW)) < currentCoordinate) {
  114. tmpRect.set(orient.get_perpendicular().get_direction(HIGH),
  115. currentCoordinate);
  116. result_type result;
  117. assign(result, tmpRect);
  118. rectangles.insert(rectangles.end(), result);
  119. }
  120. //erase the rectangle from the scan data
  121. typename ST::iterator nextIter = dataIter;
  122. ++nextIter;
  123. scanData.erase(dataIter);
  124. dataIter = nextIter;
  125. if(haveCurrentRect) {
  126. if(currentRect.get(orient).get(HIGH) >= edge.get(LOW)){
  127. if(!edgeProcessed && currentRect.get(orient.get_direction(HIGH)) > edge.get(LOW)){
  128. rectangle_type tmpRect2(currentRect);
  129. tmpRect2.set(orient.get_direction(HIGH), edge.get(LOW));
  130. scanData.insert(nextIter, tmpRect2);
  131. if(currentRect.get(orient.get_direction(HIGH)) > edge.get(HIGH)) {
  132. currentRect.set(orient, interval_data<coordinate_type>(edge.get(HIGH), currentRect.get(orient.get_direction(HIGH))));
  133. } else {
  134. haveCurrentRect = false;
  135. }
  136. } else {
  137. //extend the top of current rect
  138. currentRect.set(orient.get_direction(HIGH),
  139. (std::max)(edge.get(HIGH),
  140. tmpRect.get(orient.get_direction(HIGH))));
  141. }
  142. } else {
  143. //insert current rect into the scanData
  144. scanData.insert(nextIter, currentRect);
  145. //create a new current rect
  146. currentRect.set(orient.get_perpendicular(), interval_data<coordinate_type>(currentCoordinate,
  147. currentCoordinate));
  148. currentRect.set(orient, interval_data<coordinate_type>((std::min)(tmpRect.get(orient).get(LOW),
  149. edge.get(LOW)),
  150. (std::max)(tmpRect.get(orient).get(HIGH),
  151. edge.get(HIGH))));
  152. }
  153. } else {
  154. haveCurrentRect = true;
  155. currentRect.set(orient.get_perpendicular(), interval_data<coordinate_type>(currentCoordinate,
  156. currentCoordinate));
  157. currentRect.set(orient, interval_data<coordinate_type>((std::min)(tmpRect.get(orient).get(LOW),
  158. edge.get(LOW)),
  159. (std::max)(tmpRect.get(orient).get(HIGH),
  160. edge.get(HIGH))));
  161. }
  162. //skip to nextIter position
  163. edgeProcessed = true;
  164. continue;
  165. }
  166. //edgeProcessed = true;
  167. }
  168. ++dataIter;
  169. } //end while edge intersects rectangle data
  170. }
  171. if(!edgeProcessed) {
  172. if(haveCurrentRect) {
  173. if(currentRect.get(orient.get_perpendicular().get_direction(HIGH))
  174. == currentCoordinate &&
  175. currentRect.get(orient.get_direction(HIGH)) >= edge.get(LOW))
  176. {
  177. if(currentRect.get(orient.get_direction(HIGH)) > edge.get(LOW)){
  178. rectangle_type tmpRect(currentRect);
  179. tmpRect.set(orient.get_direction(HIGH), edge.get(LOW));
  180. scanData.insert(scanData.end(), tmpRect);
  181. if(currentRect.get(orient.get_direction(HIGH)) > edge.get(HIGH)) {
  182. currentRect.set(orient,
  183. interval_data<coordinate_type>(edge.get(HIGH),
  184. currentRect.get(orient.get_direction(HIGH))));
  185. return rectangles;
  186. } else {
  187. haveCurrentRect = false;
  188. return rectangles;
  189. }
  190. }
  191. //extend current rect
  192. currentRect.set(orient.get_direction(HIGH), edge.get(HIGH));
  193. return rectangles;
  194. }
  195. scanData.insert(scanData.end(), currentRect);
  196. haveCurrentRect = false;
  197. }
  198. rectangle_type tmpRect(currentRect);
  199. tmpRect.set(orient.get_perpendicular(), interval_data<coordinate_type>(currentCoordinate,
  200. currentCoordinate));
  201. tmpRect.set(orient, edge);
  202. scanData.insert(tmpRect);
  203. return rectangles;
  204. }
  205. return rectangles;
  206. }
  207. template <class T>
  208. template <class CT>
  209. inline
  210. ScanLineToRects<T>& ScanLineToRects<T>::processEdge(CT& rectangles, const interval_data<coordinate_type>& edge)
  211. {
  212. processEdge_(rectangles, scanData_, edge, haveCurrentRect_, currentRect_, currentCoordinate_, orient_);
  213. return *this;
  214. }
  215. } //namespace rectangle_formation
  216. template <typename T, typename T2>
  217. struct get_coordinate_type_for_rectangles {
  218. typedef typename polygon_traits<T>::coordinate_type type;
  219. };
  220. template <typename T>
  221. struct get_coordinate_type_for_rectangles<T, rectangle_concept> {
  222. typedef typename rectangle_traits<T>::coordinate_type type;
  223. };
  224. template <typename output_container, typename iterator_type, typename rectangle_concept>
  225. void form_rectangles(output_container& output, iterator_type begin, iterator_type end,
  226. orientation_2d orient, rectangle_concept ) {
  227. typedef typename output_container::value_type rectangle_type;
  228. typedef typename get_coordinate_type_for_rectangles<rectangle_type, typename geometry_concept<rectangle_type>::type>::type Unit;
  229. rectangle_data<Unit> model;
  230. Unit prevPos = (std::numeric_limits<Unit>::max)();
  231. rectangle_formation::ScanLineToRects<rectangle_data<Unit> > scanlineToRects(orient, model);
  232. for(iterator_type itr = begin;
  233. itr != end; ++ itr) {
  234. Unit pos = (*itr).first;
  235. if(pos != prevPos) {
  236. scanlineToRects.nextMajorCoordinate(pos);
  237. prevPos = pos;
  238. }
  239. Unit lowy = (*itr).second.first;
  240. iterator_type tmp_itr = itr;
  241. ++itr;
  242. Unit highy = (*itr).second.first;
  243. scanlineToRects.processEdge(output, interval_data<Unit>(lowy, highy));
  244. if(std::abs((*itr).second.second) > 1) itr = tmp_itr; //next edge begins from this vertex
  245. }
  246. }
  247. }
  248. }
  249. #endif