123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- /*
- Copyright 2008 Intel Corporation
- Use, modification and distribution are subject to the Boost Software License,
- Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- http://www.boost.org/LICENSE_1_0.txt).
- */
- #ifndef BOOST_POLYGON_BOOLEAN_OP_HPP
- #define BOOST_POLYGON_BOOLEAN_OP_HPP
- namespace boost { namespace polygon{
- namespace boolean_op {
- //BooleanOp is the generic boolean operation scanline algorithm that provides
- //all the simple boolean set operations on manhattan data. By templatizing
- //the intersection count of the input and algorithm internals it is extensible
- //to multi-layer scans, properties and other advanced scanline operations above
- //and beyond simple booleans.
- //T must cast to int
- template <class T, typename Unit>
- class BooleanOp {
- public:
- typedef std::map<Unit, T> ScanData;
- typedef std::pair<Unit, T> ElementType;
- protected:
- ScanData scanData_;
- typename ScanData::iterator nextItr_;
- T nullT_;
- public:
- inline BooleanOp () : scanData_(), nextItr_(), nullT_() { nextItr_ = scanData_.end(); nullT_ = 0; }
- inline BooleanOp (T nullT) : scanData_(), nextItr_(), nullT_(nullT) { nextItr_ = scanData_.end(); }
- inline BooleanOp (const BooleanOp& that) : scanData_(that.scanData_), nextItr_(),
- nullT_(that.nullT_) { nextItr_ = scanData_.begin(); }
- inline BooleanOp& operator=(const BooleanOp& that);
- //moves scanline forward
- inline void advanceScan() { nextItr_ = scanData_.begin(); }
- //proceses the given interval and T data
- //appends output edges to cT
- template <class cT>
- inline void processInterval(cT& outputContainer, interval_data<Unit> ivl, T deltaCount);
- private:
- inline typename ScanData::iterator lookup_(Unit pos){
- if(nextItr_ != scanData_.end() && nextItr_->first >= pos) {
- return nextItr_;
- }
- return nextItr_ = scanData_.lower_bound(pos);
- }
- inline typename ScanData::iterator insert_(Unit pos, T count){
- return nextItr_ = scanData_.insert(nextItr_, ElementType(pos, count));
- }
- template <class cT>
- inline void evaluateInterval_(cT& outputContainer, interval_data<Unit> ivl, T beforeCount, T afterCount);
- };
- class BinaryAnd {
- public:
- inline BinaryAnd() {}
- inline bool operator()(int a, int b) { return (a > 0) & (b > 0); }
- };
- class BinaryOr {
- public:
- inline BinaryOr() {}
- inline bool operator()(int a, int b) { return (a > 0) | (b > 0); }
- };
- class BinaryNot {
- public:
- inline BinaryNot() {}
- inline bool operator()(int a, int b) { return (a > 0) & !(b > 0); }
- };
- class BinaryXor {
- public:
- inline BinaryXor() {}
- inline bool operator()(int a, int b) { return (a > 0) ^ (b > 0); }
- };
- //BinaryCount is an array of two deltaCounts coming from two different layers
- //of scan event data. It is the merged count of the two suitable for consumption
- //as the template argument of the BooleanOp algorithm because BinaryCount casts to int.
- //T is a binary functor object that evaluates the array of counts and returns a logical
- //result of some operation on those values.
- //BinaryCount supports many of the operators that work with int, particularly the
- //binary operators, but cannot support less than or increment.
- template <class T>
- class BinaryCount {
- public:
- inline BinaryCount()
- #ifndef BOOST_POLYGON_MSVC
- : counts_()
- #endif
- { counts_[0] = counts_[1] = 0; }
- // constructs from two integers
- inline BinaryCount(int countL, int countR)
- #ifndef BOOST_POLYGON_MSVC
- : counts_()
- #endif
- { counts_[0] = countL, counts_[1] = countR; }
- inline BinaryCount& operator=(int count) { counts_[0] = count, counts_[1] = count; return *this; }
- inline BinaryCount& operator=(const BinaryCount& that);
- inline BinaryCount(const BinaryCount& that)
- #ifndef BOOST_POLYGON_MSVC
- : counts_()
- #endif
- { *this = that; }
- inline bool operator==(const BinaryCount& that) const;
- inline bool operator!=(const BinaryCount& that) const { return !((*this) == that);}
- inline BinaryCount& operator+=(const BinaryCount& that);
- inline BinaryCount& operator-=(const BinaryCount& that);
- inline BinaryCount operator+(const BinaryCount& that) const;
- inline BinaryCount operator-(const BinaryCount& that) const;
- inline BinaryCount operator-() const;
- inline int& operator[](bool index) { return counts_[index]; }
- //cast to int operator evaluates data using T binary functor
- inline operator int() const { return T()(counts_[0], counts_[1]); }
- private:
- int counts_[2];
- };
- class UnaryCount {
- public:
- inline UnaryCount() : count_(0) {}
- // constructs from two integers
- inline explicit UnaryCount(int count) : count_(count) {}
- inline UnaryCount& operator=(int count) { count_ = count; return *this; }
- inline UnaryCount& operator=(const UnaryCount& that) { count_ = that.count_; return *this; }
- inline UnaryCount(const UnaryCount& that) : count_(that.count_) {}
- inline bool operator==(const UnaryCount& that) const { return count_ == that.count_; }
- inline bool operator!=(const UnaryCount& that) const { return !((*this) == that);}
- inline UnaryCount& operator+=(const UnaryCount& that) { count_ += that.count_; return *this; }
- inline UnaryCount& operator-=(const UnaryCount& that) { count_ -= that.count_; return *this; }
- inline UnaryCount operator+(const UnaryCount& that) const { UnaryCount tmp(*this); tmp += that; return tmp; }
- inline UnaryCount operator-(const UnaryCount& that) const { UnaryCount tmp(*this); tmp -= that; return tmp; }
- inline UnaryCount operator-() const { UnaryCount tmp; return tmp - *this; }
- //cast to int operator evaluates data using T binary functor
- inline operator int() const { return count_ % 2; }
- private:
- int count_;
- };
- template <class T, typename Unit>
- inline BooleanOp<T, Unit>& BooleanOp<T, Unit>::operator=(const BooleanOp& that) {
- scanData_ = that.scanData_;
- nextItr_ = scanData_.begin();
- nullT_ = that.nullT_;
- return *this;
- }
- //appends output edges to cT
- template <class T, typename Unit>
- template <class cT>
- inline void BooleanOp<T, Unit>::processInterval(cT& outputContainer, interval_data<Unit> ivl, T deltaCount) {
- typename ScanData::iterator lowItr = lookup_(ivl.low());
- typename ScanData::iterator highItr = lookup_(ivl.high());
- //add interval to scan data if it is past the end
- if(lowItr == scanData_.end()) {
- lowItr = insert_(ivl.low(), deltaCount);
- highItr = insert_(ivl.high(), nullT_);
- evaluateInterval_(outputContainer, ivl, nullT_, deltaCount);
- return;
- }
- //ensure that highItr points to the end of the ivl
- if(highItr == scanData_.end() || (*highItr).first > ivl.high()) {
- T value = nullT_;
- if(highItr != scanData_.begin()) {
- --highItr;
- value = highItr->second;
- }
- nextItr_ = highItr;
- highItr = insert_(ivl.high(), value);
- }
- //split the low interval if needed
- if(lowItr->first > ivl.low()) {
- if(lowItr != scanData_.begin()) {
- --lowItr;
- nextItr_ = lowItr;
- lowItr = insert_(ivl.low(), lowItr->second);
- } else {
- nextItr_ = lowItr;
- lowItr = insert_(ivl.low(), nullT_);
- }
- }
- //process scan data intersecting interval
- for(typename ScanData::iterator itr = lowItr; itr != highItr; ){
- T beforeCount = itr->second;
- T afterCount = itr->second += deltaCount;
- Unit low = itr->first;
- ++itr;
- Unit high = itr->first;
- evaluateInterval_(outputContainer, interval_data<Unit>(low, high), beforeCount, afterCount);
- }
- //merge the bottom interval with the one below if they have the same count
- if(lowItr != scanData_.begin()){
- typename ScanData::iterator belowLowItr = lowItr;
- --belowLowItr;
- if(belowLowItr->second == lowItr->second) {
- scanData_.erase(lowItr);
- }
- }
- //merge the top interval with the one above if they have the same count
- if(highItr != scanData_.begin()) {
- typename ScanData::iterator beforeHighItr = highItr;
- --beforeHighItr;
- if(beforeHighItr->second == highItr->second) {
- scanData_.erase(highItr);
- highItr = beforeHighItr;
- ++highItr;
- }
- }
- nextItr_ = highItr;
- }
- template <class T, typename Unit>
- template <class cT>
- inline void BooleanOp<T, Unit>::evaluateInterval_(cT& outputContainer, interval_data<Unit> ivl,
- T beforeCount, T afterCount) {
- bool before = (int)beforeCount > 0;
- bool after = (int)afterCount > 0;
- int value = (!before & after) - (before & !after);
- if(value) {
- outputContainer.insert(outputContainer.end(), std::pair<interval_data<Unit>, int>(ivl, value));
- }
- }
- template <class T>
- inline BinaryCount<T>& BinaryCount<T>::operator=(const BinaryCount<T>& that) {
- counts_[0] = that.counts_[0];
- counts_[1] = that.counts_[1];
- return *this;
- }
- template <class T>
- inline bool BinaryCount<T>::operator==(const BinaryCount<T>& that) const {
- return counts_[0] == that.counts_[0] &&
- counts_[1] == that.counts_[1];
- }
- template <class T>
- inline BinaryCount<T>& BinaryCount<T>::operator+=(const BinaryCount<T>& that) {
- counts_[0] += that.counts_[0];
- counts_[1] += that.counts_[1];
- return *this;
- }
- template <class T>
- inline BinaryCount<T>& BinaryCount<T>::operator-=(const BinaryCount<T>& that) {
- counts_[0] += that.counts_[0];
- counts_[1] += that.counts_[1];
- return *this;
- }
- template <class T>
- inline BinaryCount<T> BinaryCount<T>::operator+(const BinaryCount<T>& that) const {
- BinaryCount retVal(*this);
- retVal += that;
- return retVal;
- }
- template <class T>
- inline BinaryCount<T> BinaryCount<T>::operator-(const BinaryCount<T>& that) const {
- BinaryCount retVal(*this);
- retVal -= that;
- return retVal;
- }
- template <class T>
- inline BinaryCount<T> BinaryCount<T>::operator-() const {
- return BinaryCount<T>() - *this;
- }
- template <class T, typename Unit, typename iterator_type_1, typename iterator_type_2>
- inline void applyBooleanBinaryOp(std::vector<std::pair<Unit, std::pair<Unit, int> > >& output,
- //const std::vector<std::pair<Unit, std::pair<Unit, int> > >& input1,
- //const std::vector<std::pair<Unit, std::pair<Unit, int> > >& input2,
- iterator_type_1 itr1, iterator_type_1 itr1_end,
- iterator_type_2 itr2, iterator_type_2 itr2_end,
- T defaultCount) {
- BooleanOp<T, Unit> boolean(defaultCount);
- //typename std::vector<std::pair<Unit, std::pair<Unit, int> > >::const_iterator itr1 = input1.begin();
- //typename std::vector<std::pair<Unit, std::pair<Unit, int> > >::const_iterator itr2 = input2.begin();
- std::vector<std::pair<interval_data<Unit>, int> > container;
- //output.reserve((std::max)(input1.size(), input2.size()));
- //consider eliminating dependecy on limits with bool flag for initial state
- Unit UnitMax = (std::numeric_limits<Unit>::max)();
- Unit prevCoord = UnitMax;
- Unit prevPosition = UnitMax;
- T count(defaultCount);
- //define the starting point
- if(itr1 != itr1_end) {
- prevCoord = (*itr1).first;
- prevPosition = (*itr1).second.first;
- count[0] += (*itr1).second.second;
- }
- if(itr2 != itr2_end) {
- if((*itr2).first < prevCoord ||
- ((*itr2).first == prevCoord && (*itr2).second.first < prevPosition)) {
- prevCoord = (*itr2).first;
- prevPosition = (*itr2).second.first;
- count = defaultCount;
- count[1] += (*itr2).second.second;
- ++itr2;
- } else if((*itr2).first == prevCoord && (*itr2).second.first == prevPosition) {
- count[1] += (*itr2).second.second;
- ++itr2;
- if(itr1 != itr1_end) ++itr1;
- } else {
- if(itr1 != itr1_end) ++itr1;
- }
- } else {
- if(itr1 != itr1_end) ++itr1;
- }
- while(itr1 != itr1_end || itr2 != itr2_end) {
- Unit curCoord = UnitMax;
- Unit curPosition = UnitMax;
- T curCount(defaultCount);
- if(itr1 != itr1_end) {
- curCoord = (*itr1).first;
- curPosition = (*itr1).second.first;
- curCount[0] += (*itr1).second.second;
- }
- if(itr2 != itr2_end) {
- if((*itr2).first < curCoord ||
- ((*itr2).first == curCoord && (*itr2).second.first < curPosition)) {
- curCoord = (*itr2).first;
- curPosition = (*itr2).second.first;
- curCount = defaultCount;
- curCount[1] += (*itr2).second.second;
- ++itr2;
- } else if((*itr2).first == curCoord && (*itr2).second.first == curPosition) {
- curCount[1] += (*itr2).second.second;
- ++itr2;
- if(itr1 != itr1_end) ++itr1;
- } else {
- if(itr1 != itr1_end) ++itr1;
- }
- } else {
- ++itr1;
- }
- if(prevCoord != curCoord) {
- boolean.advanceScan();
- prevCoord = curCoord;
- prevPosition = curPosition;
- count = curCount;
- continue;
- }
- if(curPosition != prevPosition && count != defaultCount) {
- interval_data<Unit> ivl(prevPosition, curPosition);
- container.clear();
- boolean.processInterval(container, ivl, count);
- for(std::size_t i = 0; i < container.size(); ++i) {
- std::pair<interval_data<Unit>, int>& element = container[i];
- if(!output.empty() && output.back().first == prevCoord &&
- output.back().second.first == element.first.low() &&
- output.back().second.second == element.second * -1) {
- output.pop_back();
- } else {
- output.push_back(std::pair<Unit, std::pair<Unit, int> >(prevCoord, std::pair<Unit, int>(element.first.low(),
- element.second)));
- }
- output.push_back(std::pair<Unit, std::pair<Unit, int> >(prevCoord, std::pair<Unit, int>(element.first.high(),
- element.second * -1)));
- }
- }
- prevPosition = curPosition;
- count += curCount;
- }
- }
- template <class T, typename Unit>
- inline void applyBooleanBinaryOp(std::vector<std::pair<Unit, std::pair<Unit, int> > >& inputOutput,
- const std::vector<std::pair<Unit, std::pair<Unit, int> > >& input2,
- T defaultCount) {
- std::vector<std::pair<Unit, std::pair<Unit, int> > > output;
- applyBooleanBinaryOp(output, inputOutput, input2, defaultCount);
- if(output.size() < inputOutput.size() / 2) {
- inputOutput = std::vector<std::pair<Unit, std::pair<Unit, int> > >();
- } else {
- inputOutput.clear();
- }
- inputOutput.insert(inputOutput.end(), output.begin(), output.end());
- }
- template <typename count_type = int>
- struct default_arg_workaround {
- template <typename Unit>
- static inline void applyBooleanOr(std::vector<std::pair<Unit, std::pair<Unit, int> > >& input) {
- BooleanOp<count_type, Unit> booleanOr;
- std::vector<std::pair<interval_data<Unit>, int> > container;
- std::vector<std::pair<Unit, std::pair<Unit, int> > > output;
- output.reserve(input.size());
- //consider eliminating dependecy on limits with bool flag for initial state
- Unit UnitMax = (std::numeric_limits<Unit>::max)();
- Unit prevPos = UnitMax;
- Unit prevY = UnitMax;
- int count = 0;
- for(typename std::vector<std::pair<Unit, std::pair<Unit, int> > >::iterator itr = input.begin();
- itr != input.end(); ++itr) {
- Unit pos = (*itr).first;
- Unit y = (*itr).second.first;
- if(pos != prevPos) {
- booleanOr.advanceScan();
- prevPos = pos;
- prevY = y;
- count = (*itr).second.second;
- continue;
- }
- if(y != prevY && count != 0) {
- interval_data<Unit> ivl(prevY, y);
- container.clear();
- booleanOr.processInterval(container, ivl, count_type(count));
- for(std::size_t i = 0; i < container.size(); ++i) {
- std::pair<interval_data<Unit>, int>& element = container[i];
- if(!output.empty() && output.back().first == prevPos &&
- output.back().second.first == element.first.low() &&
- output.back().second.second == element.second * -1) {
- output.pop_back();
- } else {
- output.push_back(std::pair<Unit, std::pair<Unit, int> >(prevPos, std::pair<Unit, int>(element.first.low(),
- element.second)));
- }
- output.push_back(std::pair<Unit, std::pair<Unit, int> >(prevPos, std::pair<Unit, int>(element.first.high(),
- element.second * -1)));
- }
- }
- prevY = y;
- count += (*itr).second.second;
- }
- if(output.size() < input.size() / 2) {
- input = std::vector<std::pair<Unit, std::pair<Unit, int> > >();
- } else {
- input.clear();
- }
- input.insert(input.end(), output.begin(), output.end());
- }
- };
- }
- }
- }
- #endif
|