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
|