1 /*
2   Copyright 2008 Intel Corporation
3 
4   Use, modification and distribution are subject to the Boost Software License,
5   Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6   http://www.boost.org/LICENSE_1_0.txt).
7 */
8 #ifndef BOOST_POLYGON_BOOLEAN_OP_HPP
9 #define BOOST_POLYGON_BOOLEAN_OP_HPP
10 namespace boost { namespace polygon{
11 namespace boolean_op {
12 
13   //BooleanOp is the generic boolean operation scanline algorithm that provides
14   //all the simple boolean set operations on manhattan data.  By templatizing
15   //the intersection count of the input and algorithm internals it is extensible
16   //to multi-layer scans, properties and other advanced scanline operations above
17   //and beyond simple booleans.
18   //T must cast to int
19   template <class T, typename Unit>
20   class BooleanOp {
21   public:
22     typedef std::map<Unit, T> ScanData;
23     typedef std::pair<Unit, T> ElementType;
24   protected:
25     ScanData scanData_;
26     typename ScanData::iterator nextItr_;
27     T nullT_;
28   public:
BooleanOp()29     inline BooleanOp () : scanData_(), nextItr_(), nullT_() { nextItr_ = scanData_.end(); nullT_ = 0; }
BooleanOp(T nullT)30     inline BooleanOp (T nullT) : scanData_(), nextItr_(), nullT_(nullT) { nextItr_ = scanData_.end(); }
BooleanOp(const BooleanOp & that)31     inline BooleanOp (const BooleanOp& that) : scanData_(that.scanData_), nextItr_(),
32                                                nullT_(that.nullT_) { nextItr_ = scanData_.begin(); }
33     inline BooleanOp& operator=(const BooleanOp& that);
34 
35     //moves scanline forward
advanceScan()36     inline void advanceScan() { nextItr_ = scanData_.begin(); }
37 
38     //proceses the given interval and T data
39     //appends output edges to cT
40     template <class cT>
41     inline void processInterval(cT& outputContainer, interval_data<Unit> ivl, T deltaCount);
42 
43   private:
lookup_(Unit pos)44     inline typename ScanData::iterator lookup_(Unit pos){
45       if(nextItr_ != scanData_.end() && nextItr_->first >= pos) {
46         return nextItr_;
47       }
48       return nextItr_ = scanData_.lower_bound(pos);
49     }
insert_(Unit pos,T count)50     inline typename ScanData::iterator insert_(Unit pos, T count){
51       return nextItr_ = scanData_.insert(nextItr_, ElementType(pos, count));
52     }
53     template <class cT>
54     inline void evaluateInterval_(cT& outputContainer, interval_data<Unit> ivl, T beforeCount, T afterCount);
55   };
56 
57   class BinaryAnd {
58   public:
BinaryAnd()59     inline BinaryAnd() {}
operator ()(int a,int b)60     inline bool operator()(int a, int b) { return (a > 0) & (b > 0); }
61   };
62   class BinaryOr {
63   public:
BinaryOr()64     inline BinaryOr() {}
operator ()(int a,int b)65     inline bool operator()(int a, int b) { return (a > 0) | (b > 0); }
66   };
67   class BinaryNot {
68   public:
BinaryNot()69     inline BinaryNot() {}
operator ()(int a,int b)70     inline bool operator()(int a, int b) { return (a > 0) & !(b > 0); }
71   };
72   class BinaryXor {
73   public:
BinaryXor()74     inline BinaryXor() {}
operator ()(int a,int b)75     inline bool operator()(int a, int b) { return (a > 0) ^ (b > 0); }
76   };
77 
78   //BinaryCount is an array of two deltaCounts coming from two different layers
79   //of scan event data.  It is the merged count of the two suitable for consumption
80   //as the template argument of the BooleanOp algorithm because BinaryCount casts to int.
81   //T is a binary functor object that evaluates the array of counts and returns a logical
82   //result of some operation on those values.
83   //BinaryCount supports many of the operators that work with int, particularly the
84   //binary operators, but cannot support less than or increment.
85   template <class T>
86   class BinaryCount {
87   public:
BinaryCount()88     inline BinaryCount()
89 #ifndef BOOST_POLYGON_MSVC
90       : counts_()
91 #endif
92     { counts_[0] = counts_[1] = 0; }
93     // constructs from two integers
BinaryCount(int countL,int countR)94     inline BinaryCount(int countL, int countR)
95 #ifndef BOOST_POLYGON_MSVC
96       : counts_()
97 #endif
98     { counts_[0] = countL, counts_[1] = countR; }
operator =(int count)99     inline BinaryCount& operator=(int count) { counts_[0] = count, counts_[1] = count; return *this; }
100     inline BinaryCount& operator=(const BinaryCount& that);
BinaryCount(const BinaryCount & that)101     inline BinaryCount(const BinaryCount& that)
102 #ifndef BOOST_POLYGON_MSVC
103       : counts_()
104 #endif
105     { *this = that; }
106     inline bool operator==(const BinaryCount& that) const;
operator !=(const BinaryCount & that) const107     inline bool operator!=(const BinaryCount& that) const { return !((*this) == that);}
108     inline BinaryCount& operator+=(const BinaryCount& that);
109     inline BinaryCount& operator-=(const BinaryCount& that);
110     inline BinaryCount operator+(const BinaryCount& that) const;
111     inline BinaryCount operator-(const BinaryCount& that) const;
112     inline BinaryCount operator-() const;
operator [](bool index)113     inline int& operator[](bool index) { return counts_[index]; }
114 
115     //cast to int operator evaluates data using T binary functor
operator int() const116     inline operator int() const { return T()(counts_[0], counts_[1]); }
117   private:
118     int counts_[2];
119   };
120 
121   class UnaryCount {
122   public:
UnaryCount()123     inline UnaryCount() : count_(0) {}
124     // constructs from two integers
UnaryCount(int count)125     inline explicit UnaryCount(int count) : count_(count) {}
operator =(int count)126     inline UnaryCount& operator=(int count) { count_ = count; return *this; }
operator =(const UnaryCount & that)127     inline UnaryCount& operator=(const UnaryCount& that) { count_ = that.count_; return *this; }
UnaryCount(const UnaryCount & that)128     inline UnaryCount(const UnaryCount& that) : count_(that.count_) {}
operator ==(const UnaryCount & that) const129     inline bool operator==(const UnaryCount& that) const { return count_ == that.count_; }
operator !=(const UnaryCount & that) const130     inline bool operator!=(const UnaryCount& that) const { return !((*this) == that);}
operator +=(const UnaryCount & that)131     inline UnaryCount& operator+=(const UnaryCount& that) { count_ += that.count_; return *this; }
operator -=(const UnaryCount & that)132     inline UnaryCount& operator-=(const UnaryCount& that) { count_ -= that.count_; return *this; }
operator +(const UnaryCount & that) const133     inline UnaryCount operator+(const UnaryCount& that) const { UnaryCount tmp(*this); tmp += that; return tmp; }
operator -(const UnaryCount & that) const134     inline UnaryCount operator-(const UnaryCount& that) const { UnaryCount tmp(*this); tmp -= that; return tmp; }
operator -() const135     inline UnaryCount operator-() const { UnaryCount tmp; return tmp - *this; }
136 
137     //cast to int operator evaluates data using T binary functor
operator int() const138     inline operator int() const { return count_ % 2; }
139   private:
140     int count_;
141   };
142 
143   template <class T, typename Unit>
operator =(const BooleanOp & that)144   inline BooleanOp<T, Unit>& BooleanOp<T, Unit>::operator=(const BooleanOp& that) {
145     scanData_ = that.scanData_;
146     nextItr_ = scanData_.begin();
147     nullT_ = that.nullT_;
148     return *this;
149   }
150 
151   //appends output edges to cT
152   template <class T, typename Unit>
153   template <class cT>
processInterval(cT & outputContainer,interval_data<Unit> ivl,T deltaCount)154   inline void BooleanOp<T, Unit>::processInterval(cT& outputContainer, interval_data<Unit> ivl, T deltaCount) {
155     typename ScanData::iterator lowItr = lookup_(ivl.low());
156     typename ScanData::iterator highItr = lookup_(ivl.high());
157     //add interval to scan data if it is past the end
158     if(lowItr == scanData_.end()) {
159       lowItr = insert_(ivl.low(), deltaCount);
160       highItr = insert_(ivl.high(), nullT_);
161       evaluateInterval_(outputContainer, ivl, nullT_, deltaCount);
162       return;
163     }
164     //ensure that highItr points to the end of the ivl
165     if(highItr == scanData_.end() || (*highItr).first > ivl.high()) {
166       T value = nullT_;
167       if(highItr != scanData_.begin()) {
168         --highItr;
169         value = highItr->second;
170       }
171       nextItr_ = highItr;
172       highItr = insert_(ivl.high(), value);
173     }
174     //split the low interval if needed
175     if(lowItr->first > ivl.low()) {
176       if(lowItr != scanData_.begin()) {
177         --lowItr;
178         nextItr_ = lowItr;
179         lowItr = insert_(ivl.low(), lowItr->second);
180       } else {
181         nextItr_ = lowItr;
182         lowItr = insert_(ivl.low(), nullT_);
183       }
184     }
185     //process scan data intersecting interval
186     for(typename ScanData::iterator itr = lowItr; itr != highItr; ){
187       T beforeCount = itr->second;
188       T afterCount = itr->second += deltaCount;
189       Unit low = itr->first;
190       ++itr;
191       Unit high = itr->first;
192       evaluateInterval_(outputContainer, interval_data<Unit>(low, high), beforeCount, afterCount);
193     }
194     //merge the bottom interval with the one below if they have the same count
195     if(lowItr != scanData_.begin()){
196       typename ScanData::iterator belowLowItr = lowItr;
197       --belowLowItr;
198       if(belowLowItr->second == lowItr->second) {
199         scanData_.erase(lowItr);
200       }
201     }
202     //merge the top interval with the one above if they have the same count
203     if(highItr != scanData_.begin()) {
204       typename ScanData::iterator beforeHighItr = highItr;
205       --beforeHighItr;
206       if(beforeHighItr->second == highItr->second) {
207         scanData_.erase(highItr);
208         highItr = beforeHighItr;
209         ++highItr;
210       }
211     }
212     nextItr_ = highItr;
213   }
214 
215   template <class T, typename Unit>
216   template <class cT>
evaluateInterval_(cT & outputContainer,interval_data<Unit> ivl,T beforeCount,T afterCount)217   inline void BooleanOp<T, Unit>::evaluateInterval_(cT& outputContainer, interval_data<Unit> ivl,
218                                               T beforeCount, T afterCount) {
219     bool before = (int)beforeCount > 0;
220     bool after = (int)afterCount > 0;
221     int value =  (!before & after) - (before & !after);
222     if(value) {
223       outputContainer.insert(outputContainer.end(), std::pair<interval_data<Unit>, int>(ivl, value));
224     }
225   }
226 
227   template <class T>
operator =(const BinaryCount<T> & that)228   inline BinaryCount<T>& BinaryCount<T>::operator=(const BinaryCount<T>& that) {
229     counts_[0] = that.counts_[0];
230     counts_[1] = that.counts_[1];
231     return *this;
232   }
233   template <class T>
operator ==(const BinaryCount<T> & that) const234   inline bool BinaryCount<T>::operator==(const BinaryCount<T>& that) const {
235     return counts_[0] == that.counts_[0] &&
236       counts_[1] == that.counts_[1];
237   }
238   template <class T>
operator +=(const BinaryCount<T> & that)239   inline BinaryCount<T>& BinaryCount<T>::operator+=(const BinaryCount<T>& that) {
240     counts_[0] += that.counts_[0];
241     counts_[1] += that.counts_[1];
242     return *this;
243   }
244   template <class T>
operator -=(const BinaryCount<T> & that)245   inline BinaryCount<T>& BinaryCount<T>::operator-=(const BinaryCount<T>& that) {
246     counts_[0] += that.counts_[0];
247     counts_[1] += that.counts_[1];
248     return *this;
249   }
250   template <class T>
operator +(const BinaryCount<T> & that) const251   inline BinaryCount<T> BinaryCount<T>::operator+(const BinaryCount<T>& that) const {
252     BinaryCount retVal(*this);
253     retVal += that;
254     return retVal;
255   }
256   template <class T>
operator -(const BinaryCount<T> & that) const257   inline BinaryCount<T> BinaryCount<T>::operator-(const BinaryCount<T>& that) const {
258     BinaryCount retVal(*this);
259     retVal -= that;
260     return retVal;
261   }
262   template <class T>
operator -() const263   inline BinaryCount<T> BinaryCount<T>::operator-() const {
264     return BinaryCount<T>() - *this;
265   }
266 
267 
268   template <class T, typename Unit, typename iterator_type_1, typename iterator_type_2>
applyBooleanBinaryOp(std::vector<std::pair<Unit,std::pair<Unit,int>>> & output,iterator_type_1 itr1,iterator_type_1 itr1_end,iterator_type_2 itr2,iterator_type_2 itr2_end,T defaultCount)269   inline void applyBooleanBinaryOp(std::vector<std::pair<Unit, std::pair<Unit, int> > >& output,
270                                    //const std::vector<std::pair<Unit, std::pair<Unit, int> > >& input1,
271                                    //const std::vector<std::pair<Unit, std::pair<Unit, int> > >& input2,
272                                    iterator_type_1 itr1, iterator_type_1 itr1_end,
273                                    iterator_type_2 itr2, iterator_type_2 itr2_end,
274                                    T defaultCount) {
275     BooleanOp<T, Unit> boolean(defaultCount);
276     //typename std::vector<std::pair<Unit, std::pair<Unit, int> > >::const_iterator itr1 = input1.begin();
277     //typename std::vector<std::pair<Unit, std::pair<Unit, int> > >::const_iterator itr2 = input2.begin();
278     std::vector<std::pair<interval_data<Unit>, int> > container;
279     //output.reserve((std::max)(input1.size(), input2.size()));
280 
281     //consider eliminating dependecy on limits with bool flag for initial state
282     Unit UnitMax = (std::numeric_limits<Unit>::max)();
283     Unit prevCoord = UnitMax;
284     Unit prevPosition = UnitMax;
285     T count(defaultCount);
286     //define the starting point
287     if(itr1 != itr1_end) {
288       prevCoord = (*itr1).first;
289       prevPosition = (*itr1).second.first;
290       count[0] += (*itr1).second.second;
291     }
292     if(itr2 != itr2_end) {
293       if((*itr2).first < prevCoord ||
294          ((*itr2).first == prevCoord && (*itr2).second.first < prevPosition)) {
295         prevCoord = (*itr2).first;
296         prevPosition = (*itr2).second.first;
297         count = defaultCount;
298         count[1] += (*itr2).second.second;
299         ++itr2;
300       } else if((*itr2).first == prevCoord && (*itr2).second.first == prevPosition) {
301         count[1] += (*itr2).second.second;
302         ++itr2;
303         if(itr1 != itr1_end) ++itr1;
304       } else {
305         if(itr1 != itr1_end) ++itr1;
306       }
307     } else {
308       if(itr1 != itr1_end) ++itr1;
309     }
310 
311     while(itr1 != itr1_end || itr2 != itr2_end) {
312       Unit curCoord = UnitMax;
313       Unit curPosition = UnitMax;
314       T curCount(defaultCount);
315       if(itr1 != itr1_end) {
316         curCoord = (*itr1).first;
317         curPosition = (*itr1).second.first;
318         curCount[0] += (*itr1).second.second;
319       }
320       if(itr2 != itr2_end) {
321         if((*itr2).first < curCoord ||
322            ((*itr2).first == curCoord && (*itr2).second.first < curPosition)) {
323           curCoord = (*itr2).first;
324           curPosition = (*itr2).second.first;
325           curCount = defaultCount;
326           curCount[1] += (*itr2).second.second;
327           ++itr2;
328         } else if((*itr2).first == curCoord && (*itr2).second.first == curPosition) {
329           curCount[1] += (*itr2).second.second;
330           ++itr2;
331           if(itr1 != itr1_end) ++itr1;
332         } else {
333           if(itr1 != itr1_end) ++itr1;
334         }
335       } else {
336         ++itr1;
337       }
338 
339       if(prevCoord != curCoord) {
340         boolean.advanceScan();
341         prevCoord = curCoord;
342         prevPosition = curPosition;
343         count = curCount;
344         continue;
345       }
346       if(curPosition != prevPosition && count != defaultCount) {
347         interval_data<Unit> ivl(prevPosition, curPosition);
348         container.clear();
349         boolean.processInterval(container, ivl, count);
350         for(std::size_t i = 0; i < container.size(); ++i) {
351           std::pair<interval_data<Unit>, int>& element = container[i];
352           if(!output.empty() && output.back().first == prevCoord &&
353              output.back().second.first == element.first.low() &&
354              output.back().second.second == element.second * -1) {
355             output.pop_back();
356           } else {
357             output.push_back(std::pair<Unit, std::pair<Unit, int> >(prevCoord, std::pair<Unit, int>(element.first.low(),
358                                                                                                     element.second)));
359           }
360           output.push_back(std::pair<Unit, std::pair<Unit, int> >(prevCoord, std::pair<Unit, int>(element.first.high(),
361                                                                                                   element.second * -1)));
362         }
363       }
364       prevPosition = curPosition;
365       count += curCount;
366     }
367   }
368 
369   template <class T, typename Unit>
applyBooleanBinaryOp(std::vector<std::pair<Unit,std::pair<Unit,int>>> & inputOutput,const std::vector<std::pair<Unit,std::pair<Unit,int>>> & input2,T defaultCount)370   inline void applyBooleanBinaryOp(std::vector<std::pair<Unit, std::pair<Unit, int> > >& inputOutput,
371                                    const std::vector<std::pair<Unit, std::pair<Unit, int> > >& input2,
372                                    T defaultCount) {
373     std::vector<std::pair<Unit, std::pair<Unit, int> > > output;
374     applyBooleanBinaryOp(output, inputOutput, input2, defaultCount);
375     if(output.size() < inputOutput.size() / 2) {
376       inputOutput = std::vector<std::pair<Unit, std::pair<Unit, int> > >();
377     } else {
378       inputOutput.clear();
379     }
380     inputOutput.insert(inputOutput.end(), output.begin(), output.end());
381   }
382 
383   template <typename Unit>
applyUnaryXOr(std::vector<std::pair<Unit,std::pair<Unit,int>>> & input)384   inline void applyUnaryXOr(std::vector<std::pair<Unit, std::pair<Unit, int> > >& input) {
385     BooleanOp<UnaryCount, Unit> booleanXOr;
386 
387   }
388 
389   template <typename count_type = int>
390   struct default_arg_workaround {
391     template <typename Unit>
applyBooleanOrboost::polygon::boolean_op::default_arg_workaround392     static inline void applyBooleanOr(std::vector<std::pair<Unit, std::pair<Unit, int> > >& input) {
393       BooleanOp<count_type, Unit> booleanOr;
394       std::vector<std::pair<interval_data<Unit>, int> > container;
395       std::vector<std::pair<Unit, std::pair<Unit, int> > > output;
396       output.reserve(input.size());
397       //consider eliminating dependecy on limits with bool flag for initial state
398       Unit UnitMax = (std::numeric_limits<Unit>::max)();
399       Unit prevPos = UnitMax;
400       Unit prevY = UnitMax;
401       int count = 0;
402       for(typename std::vector<std::pair<Unit, std::pair<Unit, int> > >::iterator itr = input.begin();
403           itr != input.end(); ++itr) {
404         Unit pos = (*itr).first;
405         Unit y = (*itr).second.first;
406         if(pos != prevPos) {
407           booleanOr.advanceScan();
408           prevPos = pos;
409           prevY = y;
410           count = (*itr).second.second;
411           continue;
412         }
413         if(y != prevY && count != 0) {
414           interval_data<Unit> ivl(prevY, y);
415           container.clear();
416           booleanOr.processInterval(container, ivl, count_type(count));
417           for(std::size_t i = 0; i < container.size(); ++i) {
418             std::pair<interval_data<Unit>, int>& element = container[i];
419             if(!output.empty() && output.back().first == prevPos &&
420                output.back().second.first == element.first.low() &&
421                output.back().second.second == element.second * -1) {
422               output.pop_back();
423             } else {
424               output.push_back(std::pair<Unit, std::pair<Unit, int> >(prevPos, std::pair<Unit, int>(element.first.low(),
425                                                                                                     element.second)));
426             }
427             output.push_back(std::pair<Unit, std::pair<Unit, int> >(prevPos, std::pair<Unit, int>(element.first.high(),
428                                                                                                   element.second * -1)));
429           }
430         }
431         prevY = y;
432         count += (*itr).second.second;
433       }
434       if(output.size() < input.size() / 2) {
435         input = std::vector<std::pair<Unit, std::pair<Unit, int> > >();
436       } else {
437       input.clear();
438       }
439       input.insert(input.end(), output.begin(), output.end());
440     }
441   };
442 
443 }
444 
445 }
446 
447 }
448 #endif
449