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_PROPERTY_MERGE_HPP
|
Chris@16
|
9 #define BOOST_POLYGON_PROPERTY_MERGE_HPP
|
Chris@16
|
10 namespace boost { namespace polygon{
|
Chris@16
|
11
|
Chris@16
|
12 template <typename coordinate_type>
|
Chris@16
|
13 class property_merge_point {
|
Chris@16
|
14 private:
|
Chris@16
|
15 coordinate_type x_, y_;
|
Chris@16
|
16 public:
|
Chris@16
|
17 inline property_merge_point() : x_(), y_() {}
|
Chris@16
|
18 inline property_merge_point(coordinate_type x, coordinate_type y) : x_(x), y_(y) {}
|
Chris@16
|
19 //use builtin assign and copy
|
Chris@16
|
20 inline bool operator==(const property_merge_point& that) const { return x_ == that.x_ && y_ == that.y_; }
|
Chris@16
|
21 inline bool operator!=(const property_merge_point& that) const { return !((*this) == that); }
|
Chris@16
|
22 inline bool operator<(const property_merge_point& that) const {
|
Chris@16
|
23 if(x_ < that.x_) return true;
|
Chris@16
|
24 if(x_ > that.x_) return false;
|
Chris@16
|
25 return y_ < that.y_;
|
Chris@16
|
26 }
|
Chris@16
|
27 inline coordinate_type x() const { return x_; }
|
Chris@16
|
28 inline coordinate_type y() const { return y_; }
|
Chris@16
|
29 inline void x(coordinate_type value) { x_ = value; }
|
Chris@16
|
30 inline void y(coordinate_type value) { y_ = value; }
|
Chris@16
|
31 };
|
Chris@16
|
32
|
Chris@16
|
33 template <typename coordinate_type>
|
Chris@16
|
34 class property_merge_interval {
|
Chris@16
|
35 private:
|
Chris@16
|
36 coordinate_type low_, high_;
|
Chris@16
|
37 public:
|
Chris@16
|
38 inline property_merge_interval() : low_(), high_() {}
|
Chris@16
|
39 inline property_merge_interval(coordinate_type low, coordinate_type high) : low_(low), high_(high) {}
|
Chris@16
|
40 //use builtin assign and copy
|
Chris@16
|
41 inline bool operator==(const property_merge_interval& that) const { return low_ == that.low_ && high_ == that.high_; }
|
Chris@16
|
42 inline bool operator!=(const property_merge_interval& that) const { return !((*this) == that); }
|
Chris@16
|
43 inline bool operator<(const property_merge_interval& that) const {
|
Chris@16
|
44 if(low_ < that.low_) return true;
|
Chris@16
|
45 if(low_ > that.low_) return false;
|
Chris@16
|
46 return high_ < that.high_;
|
Chris@16
|
47 }
|
Chris@16
|
48 inline coordinate_type low() const { return low_; }
|
Chris@16
|
49 inline coordinate_type high() const { return high_; }
|
Chris@16
|
50 inline void low(coordinate_type value) { low_ = value; }
|
Chris@16
|
51 inline void high(coordinate_type value) { high_ = value; }
|
Chris@16
|
52 };
|
Chris@16
|
53
|
Chris@16
|
54 template <typename coordinate_type, typename property_type, typename polygon_set_type, typename keytype = std::set<property_type> >
|
Chris@16
|
55 class merge_scanline {
|
Chris@16
|
56 public:
|
Chris@16
|
57 //definitions
|
Chris@16
|
58
|
Chris@16
|
59 typedef keytype property_set;
|
Chris@16
|
60 typedef std::vector<std::pair<property_type, int> > property_map;
|
Chris@16
|
61 typedef std::pair<property_merge_point<coordinate_type>, std::pair<property_type, int> > vertex_property;
|
Chris@16
|
62 typedef std::pair<property_merge_point<coordinate_type>, property_map> vertex_data;
|
Chris@16
|
63 typedef std::vector<vertex_property> property_merge_data;
|
Chris@16
|
64 //typedef std::map<property_set, polygon_set_type> Result;
|
Chris@16
|
65 typedef std::map<coordinate_type, property_map> scanline_type;
|
Chris@16
|
66 typedef typename scanline_type::iterator scanline_iterator;
|
Chris@16
|
67 typedef std::pair<property_merge_interval<coordinate_type>, std::pair<property_set, property_set> > edge_property;
|
Chris@16
|
68 typedef std::vector<edge_property> edge_property_vector;
|
Chris@16
|
69
|
Chris@16
|
70 //static public member functions
|
Chris@16
|
71
|
Chris@16
|
72 template <typename iT, typename orientation_2d_type>
|
Chris@16
|
73 static inline void
|
Chris@16
|
74 populate_property_merge_data(property_merge_data& pmd, iT input_begin, iT input_end,
|
Chris@16
|
75 const property_type& property, orientation_2d_type orient) {
|
Chris@16
|
76 for( ; input_begin != input_end; ++input_begin) {
|
Chris@16
|
77 std::pair<property_merge_point<coordinate_type>, std::pair<property_type, int> > element;
|
Chris@16
|
78 if(orient == HORIZONTAL)
|
Chris@16
|
79 element.first = property_merge_point<coordinate_type>((*input_begin).second.first, (*input_begin).first);
|
Chris@16
|
80 else
|
Chris@16
|
81 element.first = property_merge_point<coordinate_type>((*input_begin).first, (*input_begin).second.first);
|
Chris@16
|
82 element.second.first = property;
|
Chris@16
|
83 element.second.second = (*input_begin).second.second;
|
Chris@16
|
84 pmd.push_back(element);
|
Chris@16
|
85 }
|
Chris@16
|
86 }
|
Chris@16
|
87
|
Chris@16
|
88 //public member functions
|
Chris@16
|
89
|
Chris@16
|
90 merge_scanline() : output(), scanline(), currentVertex(), tmpVector(), previousY(), countFromBelow(), scanlinePosition() {}
|
Chris@16
|
91 merge_scanline(const merge_scanline& that) :
|
Chris@16
|
92 output(that.output),
|
Chris@16
|
93 scanline(that.scanline),
|
Chris@16
|
94 currentVertex(that.currentVertex),
|
Chris@16
|
95 tmpVector(that.tmpVector),
|
Chris@16
|
96 previousY(that.previousY),
|
Chris@16
|
97 countFromBelow(that.countFromBelow),
|
Chris@16
|
98 scanlinePosition(that.scanlinePosition)
|
Chris@16
|
99 {}
|
Chris@16
|
100 merge_scanline& operator=(const merge_scanline& that) {
|
Chris@16
|
101 output = that.output;
|
Chris@16
|
102 scanline = that.scanline;
|
Chris@16
|
103 currentVertex = that.currentVertex;
|
Chris@16
|
104 tmpVector = that.tmpVector;
|
Chris@16
|
105 previousY = that.previousY;
|
Chris@16
|
106 countFromBelow = that.countFromBelow;
|
Chris@16
|
107 scanlinePosition = that.scanlinePosition;
|
Chris@16
|
108 return *this;
|
Chris@16
|
109 }
|
Chris@16
|
110
|
Chris@16
|
111 template <typename result_type>
|
Chris@16
|
112 inline void perform_merge(result_type& result, property_merge_data& data) {
|
Chris@16
|
113 if(data.empty()) return;
|
Chris@16
|
114 //sort
|
Chris@16
|
115 polygon_sort(data.begin(), data.end(), less_vertex_data<vertex_property>());
|
Chris@16
|
116 //scanline
|
Chris@16
|
117 bool firstIteration = true;
|
Chris@16
|
118 scanlinePosition = scanline.end();
|
Chris@16
|
119 for(std::size_t i = 0; i < data.size(); ++i) {
|
Chris@16
|
120 if(firstIteration) {
|
Chris@16
|
121 mergeProperty(currentVertex.second, data[i].second);
|
Chris@16
|
122 currentVertex.first = data[i].first;
|
Chris@16
|
123 firstIteration = false;
|
Chris@16
|
124 } else {
|
Chris@16
|
125 if(data[i].first != currentVertex.first) {
|
Chris@16
|
126 if(data[i].first.x() != currentVertex.first.x()) {
|
Chris@16
|
127 processVertex(output);
|
Chris@16
|
128 //std::cout << scanline.size() << " ";
|
Chris@16
|
129 countFromBelow.clear(); //should already be clear
|
Chris@16
|
130 writeOutput(currentVertex.first.x(), result, output);
|
Chris@16
|
131 currentVertex.second.clear();
|
Chris@16
|
132 mergeProperty(currentVertex.second, data[i].second);
|
Chris@16
|
133 currentVertex.first = data[i].first;
|
Chris@16
|
134 //std::cout << assertRedundant(scanline) << "/" << scanline.size() << " ";
|
Chris@16
|
135 } else {
|
Chris@16
|
136 processVertex(output);
|
Chris@16
|
137 currentVertex.second.clear();
|
Chris@16
|
138 mergeProperty(currentVertex.second, data[i].second);
|
Chris@16
|
139 currentVertex.first = data[i].first;
|
Chris@16
|
140 }
|
Chris@16
|
141 } else {
|
Chris@16
|
142 mergeProperty(currentVertex.second, data[i].second);
|
Chris@16
|
143 }
|
Chris@16
|
144 }
|
Chris@16
|
145 }
|
Chris@16
|
146 processVertex(output);
|
Chris@16
|
147 writeOutput(currentVertex.first.x(), result, output);
|
Chris@16
|
148 //std::cout << assertRedundant(scanline) << "/" << scanline.size() << "\n";
|
Chris@16
|
149 //std::cout << scanline.size() << "\n";
|
Chris@16
|
150 }
|
Chris@16
|
151
|
Chris@16
|
152 private:
|
Chris@16
|
153 //private supporting types
|
Chris@16
|
154
|
Chris@16
|
155 template <class T>
|
Chris@16
|
156 class less_vertex_data {
|
Chris@16
|
157 public:
|
Chris@16
|
158 less_vertex_data() {}
|
Chris@16
|
159 bool operator()(const T& lvalue, const T& rvalue) const {
|
Chris@16
|
160 if(lvalue.first.x() < rvalue.first.x()) return true;
|
Chris@16
|
161 if(lvalue.first.x() > rvalue.first.x()) return false;
|
Chris@16
|
162 if(lvalue.first.y() < rvalue.first.y()) return true;
|
Chris@16
|
163 return false;
|
Chris@16
|
164 }
|
Chris@16
|
165 };
|
Chris@16
|
166
|
Chris@16
|
167 template <typename T>
|
Chris@16
|
168 struct lessPropertyCount {
|
Chris@16
|
169 lessPropertyCount() {}
|
Chris@16
|
170 bool operator()(const T& a, const T& b) {
|
Chris@16
|
171 return a.first < b.first;
|
Chris@16
|
172 }
|
Chris@16
|
173 };
|
Chris@16
|
174
|
Chris@16
|
175 //private static member functions
|
Chris@16
|
176
|
Chris@16
|
177 static inline void mergeProperty(property_map& lvalue, std::pair<property_type, int>& rvalue) {
|
Chris@16
|
178 typename property_map::iterator itr = std::lower_bound(lvalue.begin(), lvalue.end(), rvalue,
|
Chris@16
|
179 lessPropertyCount<std::pair<property_type, int> >());
|
Chris@16
|
180 if(itr == lvalue.end() ||
|
Chris@16
|
181 (*itr).first != rvalue.first) {
|
Chris@16
|
182 lvalue.insert(itr, rvalue);
|
Chris@16
|
183 } else {
|
Chris@16
|
184 (*itr).second += rvalue.second;
|
Chris@16
|
185 if((*itr).second == 0)
|
Chris@16
|
186 lvalue.erase(itr);
|
Chris@16
|
187 }
|
Chris@16
|
188 // if(assertSorted(lvalue)) {
|
Chris@16
|
189 // std::cout << "in mergeProperty\n";
|
Chris@16
|
190 // exit(0);
|
Chris@16
|
191 // }
|
Chris@16
|
192 }
|
Chris@16
|
193
|
Chris@16
|
194 // static inline bool assertSorted(property_map& pset) {
|
Chris@16
|
195 // bool result = false;
|
Chris@16
|
196 // for(std::size_t i = 1; i < pset.size(); ++i) {
|
Chris@16
|
197 // if(pset[i] < pset[i-1]) {
|
Chris@16
|
198 // std::cout << "Out of Order Error ";
|
Chris@16
|
199 // result = true;
|
Chris@16
|
200 // }
|
Chris@16
|
201 // if(pset[i].first == pset[i-1].first) {
|
Chris@16
|
202 // std::cout << "Duplicate Property Error ";
|
Chris@16
|
203 // result = true;
|
Chris@16
|
204 // }
|
Chris@16
|
205 // if(pset[0].second == 0 || pset[1].second == 0) {
|
Chris@16
|
206 // std::cout << "Empty Property Error ";
|
Chris@16
|
207 // result = true;
|
Chris@16
|
208 // }
|
Chris@16
|
209 // }
|
Chris@16
|
210 // return result;
|
Chris@16
|
211 // }
|
Chris@16
|
212
|
Chris@16
|
213 static inline void setProperty(property_set& pset, property_map& pmap) {
|
Chris@16
|
214 for(typename property_map::iterator itr = pmap.begin(); itr != pmap.end(); ++itr) {
|
Chris@16
|
215 if((*itr).second > 0) {
|
Chris@16
|
216 pset.insert(pset.end(), (*itr).first);
|
Chris@16
|
217 }
|
Chris@16
|
218 }
|
Chris@16
|
219 }
|
Chris@16
|
220
|
Chris@16
|
221 //private data members
|
Chris@16
|
222
|
Chris@16
|
223 edge_property_vector output;
|
Chris@16
|
224 scanline_type scanline;
|
Chris@16
|
225 vertex_data currentVertex;
|
Chris@16
|
226 property_map tmpVector;
|
Chris@16
|
227 coordinate_type previousY;
|
Chris@16
|
228 property_map countFromBelow;
|
Chris@16
|
229 scanline_iterator scanlinePosition;
|
Chris@16
|
230
|
Chris@16
|
231 //private member functions
|
Chris@16
|
232
|
Chris@16
|
233 inline void mergeCount(property_map& lvalue, property_map& rvalue) {
|
Chris@16
|
234 typename property_map::iterator litr = lvalue.begin();
|
Chris@16
|
235 typename property_map::iterator ritr = rvalue.begin();
|
Chris@16
|
236 tmpVector.clear();
|
Chris@16
|
237 while(litr != lvalue.end() && ritr != rvalue.end()) {
|
Chris@16
|
238 if((*litr).first <= (*ritr).first) {
|
Chris@16
|
239 if(!tmpVector.empty() &&
|
Chris@16
|
240 (*litr).first == tmpVector.back().first) {
|
Chris@16
|
241 tmpVector.back().second += (*litr).second;
|
Chris@16
|
242 } else {
|
Chris@16
|
243 tmpVector.push_back(*litr);
|
Chris@16
|
244 }
|
Chris@16
|
245 ++litr;
|
Chris@16
|
246 } else if((*ritr).first <= (*litr).first) {
|
Chris@16
|
247 if(!tmpVector.empty() &&
|
Chris@16
|
248 (*ritr).first == tmpVector.back().first) {
|
Chris@16
|
249 tmpVector.back().second += (*ritr).second;
|
Chris@16
|
250 } else {
|
Chris@16
|
251 tmpVector.push_back(*ritr);
|
Chris@16
|
252 }
|
Chris@16
|
253 ++ritr;
|
Chris@16
|
254 }
|
Chris@16
|
255 }
|
Chris@16
|
256 while(litr != lvalue.end()) {
|
Chris@16
|
257 if(!tmpVector.empty() &&
|
Chris@16
|
258 (*litr).first == tmpVector.back().first) {
|
Chris@16
|
259 tmpVector.back().second += (*litr).second;
|
Chris@16
|
260 } else {
|
Chris@16
|
261 tmpVector.push_back(*litr);
|
Chris@16
|
262 }
|
Chris@16
|
263 ++litr;
|
Chris@16
|
264 }
|
Chris@16
|
265 while(ritr != rvalue.end()) {
|
Chris@16
|
266 if(!tmpVector.empty() &&
|
Chris@16
|
267 (*ritr).first == tmpVector.back().first) {
|
Chris@16
|
268 tmpVector.back().second += (*ritr).second;
|
Chris@16
|
269 } else {
|
Chris@16
|
270 tmpVector.push_back(*ritr);
|
Chris@16
|
271 }
|
Chris@16
|
272 ++ritr;
|
Chris@16
|
273 }
|
Chris@16
|
274 lvalue.clear();
|
Chris@16
|
275 for(std::size_t i = 0; i < tmpVector.size(); ++i) {
|
Chris@16
|
276 if(tmpVector[i].second != 0) {
|
Chris@16
|
277 lvalue.push_back(tmpVector[i]);
|
Chris@16
|
278 }
|
Chris@16
|
279 }
|
Chris@16
|
280 // if(assertSorted(lvalue)) {
|
Chris@16
|
281 // std::cout << "in mergeCount\n";
|
Chris@16
|
282 // exit(0);
|
Chris@16
|
283 // }
|
Chris@16
|
284 }
|
Chris@16
|
285
|
Chris@16
|
286 inline void processVertex(edge_property_vector& output) {
|
Chris@16
|
287 if(!countFromBelow.empty()) {
|
Chris@16
|
288 //we are processing an interval of change in scanline state between
|
Chris@16
|
289 //previous vertex position and current vertex position where
|
Chris@16
|
290 //count from below represents the change on the interval
|
Chris@16
|
291 //foreach scanline element from previous to current we
|
Chris@16
|
292 //write the interval on the scanline that is changing
|
Chris@16
|
293 //the old value and the new value to output
|
Chris@16
|
294 property_merge_interval<coordinate_type> currentInterval(previousY, currentVertex.first.y());
|
Chris@16
|
295 coordinate_type currentY = currentInterval.low();
|
Chris@16
|
296 if(scanlinePosition == scanline.end() ||
|
Chris@16
|
297 (*scanlinePosition).first != previousY) {
|
Chris@16
|
298 scanlinePosition = scanline.lower_bound(previousY);
|
Chris@16
|
299 }
|
Chris@16
|
300 scanline_iterator previousScanlinePosition = scanlinePosition;
|
Chris@16
|
301 ++scanlinePosition;
|
Chris@16
|
302 while(scanlinePosition != scanline.end()) {
|
Chris@16
|
303 coordinate_type elementY = (*scanlinePosition).first;
|
Chris@16
|
304 if(elementY <= currentInterval.high()) {
|
Chris@16
|
305 property_map& countOnLeft = (*previousScanlinePosition).second;
|
Chris@16
|
306 edge_property element;
|
Chris@16
|
307 output.push_back(element);
|
Chris@16
|
308 output.back().first = property_merge_interval<coordinate_type>((*previousScanlinePosition).first, elementY);
|
Chris@16
|
309 setProperty(output.back().second.first, countOnLeft);
|
Chris@16
|
310 mergeCount(countOnLeft, countFromBelow);
|
Chris@16
|
311 setProperty(output.back().second.second, countOnLeft);
|
Chris@16
|
312 if(output.back().second.first == output.back().second.second) {
|
Chris@16
|
313 output.pop_back(); //it was an internal vertical edge, not to be output
|
Chris@16
|
314 }
|
Chris@16
|
315 else if(output.size() > 1) {
|
Chris@16
|
316 edge_property& secondToLast = output[output.size()-2];
|
Chris@16
|
317 if(secondToLast.first.high() == output.back().first.low() &&
|
Chris@16
|
318 secondToLast.second.first == output.back().second.first &&
|
Chris@16
|
319 secondToLast.second.second == output.back().second.second) {
|
Chris@16
|
320 //merge output onto previous output because properties are
|
Chris@16
|
321 //identical on both sides implying an internal horizontal edge
|
Chris@16
|
322 secondToLast.first.high(output.back().first.high());
|
Chris@16
|
323 output.pop_back();
|
Chris@16
|
324 }
|
Chris@16
|
325 }
|
Chris@16
|
326 if(previousScanlinePosition == scanline.begin()) {
|
Chris@16
|
327 if(countOnLeft.empty()) {
|
Chris@16
|
328 scanline.erase(previousScanlinePosition);
|
Chris@16
|
329 }
|
Chris@16
|
330 } else {
|
Chris@16
|
331 scanline_iterator tmpitr = previousScanlinePosition;
|
Chris@16
|
332 --tmpitr;
|
Chris@16
|
333 if((*tmpitr).second == (*previousScanlinePosition).second)
|
Chris@16
|
334 scanline.erase(previousScanlinePosition);
|
Chris@16
|
335 }
|
Chris@16
|
336
|
Chris@16
|
337 } else if(currentY < currentInterval.high()){
|
Chris@16
|
338 //elementY > currentInterval.high()
|
Chris@16
|
339 //split the interval between previous and current scanline elements
|
Chris@16
|
340 std::pair<coordinate_type, property_map> elementScan;
|
Chris@16
|
341 elementScan.first = currentInterval.high();
|
Chris@16
|
342 elementScan.second = (*previousScanlinePosition).second;
|
Chris@16
|
343 scanlinePosition = scanline.insert(scanlinePosition, elementScan);
|
Chris@16
|
344 continue;
|
Chris@16
|
345 } else {
|
Chris@16
|
346 break;
|
Chris@16
|
347 }
|
Chris@16
|
348 previousScanlinePosition = scanlinePosition;
|
Chris@16
|
349 currentY = previousY = elementY;
|
Chris@16
|
350 ++scanlinePosition;
|
Chris@16
|
351 if(scanlinePosition == scanline.end() &&
|
Chris@16
|
352 currentY < currentInterval.high()) {
|
Chris@16
|
353 //insert a new element for top of range
|
Chris@16
|
354 std::pair<coordinate_type, property_map> elementScan;
|
Chris@16
|
355 elementScan.first = currentInterval.high();
|
Chris@16
|
356 scanlinePosition = scanline.insert(scanline.end(), elementScan);
|
Chris@16
|
357 }
|
Chris@16
|
358 }
|
Chris@16
|
359 if(scanlinePosition == scanline.end() &&
|
Chris@16
|
360 currentY < currentInterval.high()) {
|
Chris@16
|
361 //handle case where we iterated to end of the scanline
|
Chris@16
|
362 //we need to insert an element into the scanline at currentY
|
Chris@16
|
363 //with property value coming from below
|
Chris@16
|
364 //and another one at currentInterval.high() with empty property value
|
Chris@16
|
365 mergeCount(scanline[currentY], countFromBelow);
|
Chris@16
|
366 std::pair<coordinate_type, property_map> elementScan;
|
Chris@16
|
367 elementScan.first = currentInterval.high();
|
Chris@16
|
368 scanline.insert(scanline.end(), elementScan);
|
Chris@16
|
369
|
Chris@16
|
370 edge_property element;
|
Chris@16
|
371 output.push_back(element);
|
Chris@16
|
372 output.back().first = property_merge_interval<coordinate_type>(currentY, currentInterval.high());
|
Chris@16
|
373 setProperty(output.back().second.second, countFromBelow);
|
Chris@16
|
374 mergeCount(countFromBelow, currentVertex.second);
|
Chris@16
|
375 } else {
|
Chris@16
|
376 mergeCount(countFromBelow, currentVertex.second);
|
Chris@16
|
377 if(countFromBelow.empty()) {
|
Chris@16
|
378 if(previousScanlinePosition == scanline.begin()) {
|
Chris@16
|
379 if((*previousScanlinePosition).second.empty()) {
|
Chris@16
|
380 scanline.erase(previousScanlinePosition);
|
Chris@16
|
381 //previousScanlinePosition = scanline.end();
|
Chris@16
|
382 //std::cout << "ERASE_A ";
|
Chris@16
|
383 }
|
Chris@16
|
384 } else {
|
Chris@16
|
385 scanline_iterator tmpitr = previousScanlinePosition;
|
Chris@16
|
386 --tmpitr;
|
Chris@16
|
387 if((*tmpitr).second == (*previousScanlinePosition).second) {
|
Chris@16
|
388 scanline.erase(previousScanlinePosition);
|
Chris@16
|
389 //previousScanlinePosition = scanline.end();
|
Chris@16
|
390 //std::cout << "ERASE_B ";
|
Chris@16
|
391 }
|
Chris@16
|
392 }
|
Chris@16
|
393 }
|
Chris@16
|
394 }
|
Chris@16
|
395 } else {
|
Chris@16
|
396 //count from below is empty, we are starting a new interval of change
|
Chris@16
|
397 countFromBelow = currentVertex.second;
|
Chris@16
|
398 scanlinePosition = scanline.lower_bound(currentVertex.first.y());
|
Chris@16
|
399 if(scanlinePosition != scanline.end()) {
|
Chris@16
|
400 if((*scanlinePosition).first != currentVertex.first.y()) {
|
Chris@16
|
401 if(scanlinePosition != scanline.begin()) {
|
Chris@16
|
402 //decrement to get the lower position of the first interval this vertex intersects
|
Chris@16
|
403 --scanlinePosition;
|
Chris@16
|
404 //insert a new element into the scanline for the incoming vertex
|
Chris@16
|
405 property_map& countOnLeft = (*scanlinePosition).second;
|
Chris@16
|
406 std::pair<coordinate_type, property_map> element(currentVertex.first.y(), countOnLeft);
|
Chris@16
|
407 scanlinePosition = scanline.insert(scanlinePosition, element);
|
Chris@16
|
408 } else {
|
Chris@16
|
409 property_map countOnLeft;
|
Chris@16
|
410 std::pair<coordinate_type, property_map> element(currentVertex.first.y(), countOnLeft);
|
Chris@16
|
411 scanlinePosition = scanline.insert(scanlinePosition, element);
|
Chris@16
|
412 }
|
Chris@16
|
413 }
|
Chris@16
|
414 } else {
|
Chris@16
|
415 property_map countOnLeft;
|
Chris@16
|
416 std::pair<coordinate_type, property_map> element(currentVertex.first.y(), countOnLeft);
|
Chris@16
|
417 scanlinePosition = scanline.insert(scanlinePosition, element);
|
Chris@16
|
418 }
|
Chris@16
|
419 }
|
Chris@16
|
420 previousY = currentVertex.first.y();
|
Chris@16
|
421 }
|
Chris@16
|
422
|
Chris@16
|
423 template <typename T>
|
Chris@16
|
424 inline int assertRedundant(T& t) {
|
Chris@16
|
425 if(t.empty()) return 0;
|
Chris@16
|
426 int count = 0;
|
Chris@16
|
427 typename T::iterator itr = t.begin();
|
Chris@16
|
428 if((*itr).second.empty())
|
Chris@16
|
429 ++count;
|
Chris@16
|
430 typename T::iterator itr2 = itr;
|
Chris@16
|
431 ++itr2;
|
Chris@16
|
432 while(itr2 != t.end()) {
|
Chris@16
|
433 if((*itr).second == (*itr2).second)
|
Chris@16
|
434 ++count;
|
Chris@16
|
435 itr = itr2;
|
Chris@16
|
436 ++itr2;
|
Chris@16
|
437 }
|
Chris@16
|
438 return count;
|
Chris@16
|
439 }
|
Chris@16
|
440
|
Chris@16
|
441 template <typename T>
|
Chris@16
|
442 inline void performExtract(T& result, property_merge_data& data) {
|
Chris@16
|
443 if(data.empty()) return;
|
Chris@16
|
444 //sort
|
Chris@16
|
445 polygon_sort(data.begin(), data.end(), less_vertex_data<vertex_property>());
|
Chris@16
|
446
|
Chris@16
|
447 //scanline
|
Chris@16
|
448 bool firstIteration = true;
|
Chris@16
|
449 scanlinePosition = scanline.end();
|
Chris@16
|
450 for(std::size_t i = 0; i < data.size(); ++i) {
|
Chris@16
|
451 if(firstIteration) {
|
Chris@16
|
452 mergeProperty(currentVertex.second, data[i].second);
|
Chris@16
|
453 currentVertex.first = data[i].first;
|
Chris@16
|
454 firstIteration = false;
|
Chris@16
|
455 } else {
|
Chris@16
|
456 if(data[i].first != currentVertex.first) {
|
Chris@16
|
457 if(data[i].first.x() != currentVertex.first.x()) {
|
Chris@16
|
458 processVertex(output);
|
Chris@16
|
459 //std::cout << scanline.size() << " ";
|
Chris@16
|
460 countFromBelow.clear(); //should already be clear
|
Chris@16
|
461 writeGraph(currentVertex.first.x(), result, output, scanline);
|
Chris@16
|
462 currentVertex.second.clear();
|
Chris@16
|
463 mergeProperty(currentVertex.second, data[i].second);
|
Chris@16
|
464 currentVertex.first = data[i].first;
|
Chris@16
|
465 } else {
|
Chris@16
|
466 processVertex(output);
|
Chris@16
|
467 currentVertex.second.clear();
|
Chris@16
|
468 mergeProperty(currentVertex.second, data[i].second);
|
Chris@16
|
469 currentVertex.first = data[i].first;
|
Chris@16
|
470 }
|
Chris@16
|
471 } else {
|
Chris@16
|
472 mergeProperty(currentVertex.second, data[i].second);
|
Chris@16
|
473 }
|
Chris@16
|
474 }
|
Chris@16
|
475 }
|
Chris@16
|
476 processVertex(output);
|
Chris@16
|
477 writeGraph(currentVertex.first.x(), result, output, scanline);
|
Chris@16
|
478 //std::cout << scanline.size() << "\n";
|
Chris@16
|
479 }
|
Chris@16
|
480
|
Chris@16
|
481 template <typename T>
|
Chris@16
|
482 inline void insertEdges(T& graph, property_set& p1, property_set& p2) {
|
Chris@16
|
483 for(typename property_set::iterator itr = p1.begin(); itr != p1.end(); ++itr) {
|
Chris@16
|
484 for(typename property_set::iterator itr2 = p2.begin(); itr2 != p2.end(); ++itr2) {
|
Chris@16
|
485 if(*itr != *itr2) {
|
Chris@16
|
486 graph[*itr].insert(*itr2);
|
Chris@16
|
487 graph[*itr2].insert(*itr);
|
Chris@16
|
488 }
|
Chris@16
|
489 }
|
Chris@16
|
490 }
|
Chris@16
|
491 }
|
Chris@16
|
492
|
Chris@16
|
493 template <typename T>
|
Chris@16
|
494 inline void propertySetAbove(coordinate_type y, property_set& ps, T& scanline) {
|
Chris@16
|
495 ps.clear();
|
Chris@16
|
496 typename T::iterator itr = scanline.find(y);
|
Chris@16
|
497 if(itr != scanline.end())
|
Chris@16
|
498 setProperty(ps, (*itr).second);
|
Chris@16
|
499 }
|
Chris@16
|
500
|
Chris@16
|
501 template <typename T>
|
Chris@16
|
502 inline void propertySetBelow(coordinate_type y, property_set& ps, T& scanline) {
|
Chris@16
|
503 ps.clear();
|
Chris@16
|
504 typename T::iterator itr = scanline.find(y);
|
Chris@16
|
505 if(itr != scanline.begin()) {
|
Chris@16
|
506 --itr;
|
Chris@16
|
507 setProperty(ps, (*itr).second);
|
Chris@16
|
508 }
|
Chris@16
|
509 }
|
Chris@16
|
510
|
Chris@16
|
511 template <typename T, typename T2>
|
Chris@16
|
512 inline void writeGraph(coordinate_type x, T& graph, edge_property_vector& output, T2& scanline) {
|
Chris@16
|
513 if(output.empty()) return;
|
Chris@16
|
514 edge_property* previousEdgeP = &(output[0]);
|
Chris@16
|
515 bool firstIteration = true;
|
Chris@16
|
516 property_set ps;
|
Chris@16
|
517 for(std::size_t i = 0; i < output.size(); ++i) {
|
Chris@16
|
518 edge_property& previousEdge = *previousEdgeP;
|
Chris@16
|
519 edge_property& edge = output[i];
|
Chris@16
|
520 if(previousEdge.first.high() == edge.first.low()) {
|
Chris@16
|
521 //horizontal edge
|
Chris@16
|
522 insertEdges(graph, edge.second.first, previousEdge.second.first);
|
Chris@16
|
523 //corner 1
|
Chris@16
|
524 insertEdges(graph, edge.second.first, previousEdge.second.second);
|
Chris@16
|
525 //other horizontal edge
|
Chris@16
|
526 insertEdges(graph, edge.second.second, previousEdge.second.second);
|
Chris@16
|
527 //corner 2
|
Chris@16
|
528 insertEdges(graph, edge.second.second, previousEdge.second.first);
|
Chris@16
|
529 } else {
|
Chris@16
|
530 if(!firstIteration){
|
Chris@16
|
531 //look up regions above previous edge
|
Chris@16
|
532 propertySetAbove(previousEdge.first.high(), ps, scanline);
|
Chris@16
|
533 insertEdges(graph, ps, previousEdge.second.first);
|
Chris@16
|
534 insertEdges(graph, ps, previousEdge.second.second);
|
Chris@16
|
535 }
|
Chris@16
|
536 //look up regions below current edge in the scanline
|
Chris@16
|
537 propertySetBelow(edge.first.high(), ps, scanline);
|
Chris@16
|
538 insertEdges(graph, ps, edge.second.first);
|
Chris@16
|
539 insertEdges(graph, ps, edge.second.second);
|
Chris@16
|
540 }
|
Chris@16
|
541 firstIteration = false;
|
Chris@16
|
542 //vertical edge
|
Chris@16
|
543 insertEdges(graph, edge.second.second, edge.second.first);
|
Chris@16
|
544 //shared region to left
|
Chris@16
|
545 insertEdges(graph, edge.second.second, edge.second.second);
|
Chris@16
|
546 //shared region to right
|
Chris@16
|
547 insertEdges(graph, edge.second.first, edge.second.first);
|
Chris@16
|
548 previousEdgeP = &(output[i]);
|
Chris@16
|
549 }
|
Chris@16
|
550 edge_property& previousEdge = *previousEdgeP;
|
Chris@16
|
551 propertySetAbove(previousEdge.first.high(), ps, scanline);
|
Chris@16
|
552 insertEdges(graph, ps, previousEdge.second.first);
|
Chris@16
|
553 insertEdges(graph, ps, previousEdge.second.second);
|
Chris@16
|
554 output.clear();
|
Chris@16
|
555 }
|
Chris@16
|
556
|
Chris@16
|
557 template <typename Result>
|
Chris@16
|
558 inline void writeOutput(coordinate_type x, Result& result, edge_property_vector& output) {
|
Chris@16
|
559 for(std::size_t i = 0; i < output.size(); ++i) {
|
Chris@16
|
560 edge_property& edge = output[i];
|
Chris@16
|
561 //edge.second.first is the property set on the left of the edge
|
Chris@16
|
562 if(!edge.second.first.empty()) {
|
Chris@16
|
563 typename Result::iterator itr = result.find(edge.second.first);
|
Chris@16
|
564 if(itr == result.end()) {
|
Chris@16
|
565 std::pair<property_set, polygon_set_type> element(edge.second.first, polygon_set_type(VERTICAL));
|
Chris@16
|
566 itr = result.insert(result.end(), element);
|
Chris@16
|
567 }
|
Chris@16
|
568 std::pair<interval_data<coordinate_type>, int> element2(interval_data<coordinate_type>(edge.first.low(), edge.first.high()), -1); //right edge of figure
|
Chris@16
|
569 (*itr).second.insert(x, element2);
|
Chris@16
|
570 }
|
Chris@16
|
571 if(!edge.second.second.empty()) {
|
Chris@16
|
572 //edge.second.second is the property set on the right of the edge
|
Chris@16
|
573 typename Result::iterator itr = result.find(edge.second.second);
|
Chris@16
|
574 if(itr == result.end()) {
|
Chris@16
|
575 std::pair<property_set, polygon_set_type> element(edge.second.second, polygon_set_type(VERTICAL));
|
Chris@16
|
576 itr = result.insert(result.end(), element);
|
Chris@16
|
577 }
|
Chris@16
|
578 std::pair<interval_data<coordinate_type>, int> element3(interval_data<coordinate_type>(edge.first.low(), edge.first.high()), 1); //left edge of figure
|
Chris@16
|
579 (*itr).second.insert(x, element3);
|
Chris@16
|
580 }
|
Chris@16
|
581 }
|
Chris@16
|
582 output.clear();
|
Chris@16
|
583 }
|
Chris@16
|
584 };
|
Chris@16
|
585
|
Chris@16
|
586 }
|
Chris@16
|
587 }
|
Chris@16
|
588 #endif
|