annotate DEPENDENCIES/generic/include/boost/polygon/detail/rectangle_formation.hpp @ 133:4acb5d8d80b6 tip

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