diff options
author | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
commit | 1a78a62555be32868418fe52f8e330c9d0f95d5a (patch) | |
tree | d3765a80e7d3b9640ec2e930743630cd6b9fce2b /boost/polygon | |
download | boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.gz boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.bz2 boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.zip |
Imported Upstream version 1.49.0upstream/1.49.0
Diffstat (limited to 'boost/polygon')
55 files changed, 28451 insertions, 0 deletions
diff --git a/boost/polygon/detail/boolean_op.hpp b/boost/polygon/detail/boolean_op.hpp new file mode 100644 index 0000000000..400825eb1f --- /dev/null +++ b/boost/polygon/detail/boolean_op.hpp @@ -0,0 +1,448 @@ +/* + 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 Unit> + inline void applyUnaryXOr(std::vector<std::pair<Unit, std::pair<Unit, int> > >& input) { + BooleanOp<UnaryCount, Unit> booleanXOr; + + } + + 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 diff --git a/boost/polygon/detail/boolean_op_45.hpp b/boost/polygon/detail/boolean_op_45.hpp new file mode 100644 index 0000000000..b4a82d8633 --- /dev/null +++ b/boost/polygon/detail/boolean_op_45.hpp @@ -0,0 +1,1394 @@ +/* + 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_45_HPP +#define BOOST_POLYGON_BOOLEAN_OP_45_HPP +namespace boost { namespace polygon{ + + template <typename Unit> + struct boolean_op_45 { + typedef point_data<Unit> Point; + typedef typename coordinate_traits<Unit>::manhattan_area_type LongUnit; + + class Count2 { + public: + inline Count2() +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { counts[0] = counts[1] = 0; } + //inline Count2(int count) { counts[0] = counts[1] = count; } + inline Count2(int count1, int count2) +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { counts[0] = count1; counts[1] = count2; } + inline Count2(const Count2& count) +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { counts[0] = count.counts[0]; counts[1] = count.counts[1]; } + inline bool operator==(const Count2& count) const { return counts[0] == count.counts[0] && counts[1] == count.counts[1]; } + inline bool operator!=(const Count2& count) const { return !((*this) == count); } + inline Count2& operator=(int count) { counts[0] = counts[1] = count; return *this; } + inline Count2& operator=(const Count2& count) { counts[0] = count.counts[0]; counts[1] = count.counts[1]; return *this; } + inline int& operator[](bool index) { return counts[index]; } + inline int operator[](bool index) const {return counts[index]; } + inline Count2& operator+=(const Count2& count){ + counts[0] += count[0]; + counts[1] += count[1]; + return *this; + } + inline Count2& operator-=(const Count2& count){ + counts[0] -= count[0]; + counts[1] -= count[1]; + return *this; + } + inline Count2 operator+(const Count2& count) const { + return Count2(*this)+=count; + } + inline Count2 operator-(const Count2& count) const { + return Count2(*this)-=count; + } + inline Count2 invert() const { + return Count2(-counts[0], -counts[1]); + } + private: + int counts[2]; + }; + + class Count1 { + public: + inline Count1() : count_(0) { } + inline Count1(int count) : count_(count) { } + inline Count1(const Count1& count) : count_(count.count_) { } + inline bool operator==(const Count1& count) const { return count_ == count.count_; } + inline bool operator!=(const Count1& count) const { return !((*this) == count); } + inline Count1& operator=(int count) { count_ = count; return *this; } + inline Count1& operator=(const Count1& count) { count_ = count.count_; return *this; } + inline Count1& operator+=(const Count1& count){ + count_ += count.count_; + return *this; + } + inline Count1& operator-=(const Count1& count){ + count_ -= count.count_; + return *this; + } + inline Count1 operator+(const Count1& count) const { + return Count1(*this)+=count; + } + inline Count1 operator-(const Count1& count) const { + return Count1(*this)-=count; + } + inline Count1 invert() const { + return Count1(-count_); + } + int count_; + }; + + // inline std::ostream& operator<< (std::ostream& o, const Count2& c) { + // o << c[0] << " " << c[1]; + // return o; + // } + + template <typename CountType> + class Scan45ElementT { + public: + Unit x; + Unit y; + int rise; //-1, 0, +1 + mutable CountType count; + inline Scan45ElementT() : x(), y(), rise(), count() {} + inline Scan45ElementT(Unit xIn, Unit yIn, int riseIn, CountType countIn = CountType()) : + x(xIn), y(yIn), rise(riseIn), count(countIn) {} + inline Scan45ElementT(const Scan45ElementT& that) : + x(that.x), y(that.y), rise(that.rise), count(that.count) {} + inline Scan45ElementT& operator=(const Scan45ElementT& that) { + x = that.x; y = that.y; rise = that.rise; count = that.count; + return *this; + } + inline Unit evalAtX(Unit xIn) const { + return y + rise * (xIn - x); + } + + inline bool cross(Point& crossPoint, const Scan45ElementT& edge, Unit currentX) const { + Unit y1 = evalAtX(currentX); + Unit y2 = edge.evalAtX(currentX); + int rise1 = rise; + int rise2 = edge.rise; + if(rise > edge.rise){ + if(y1 > y2) return false; + } else if(rise < edge.rise){ + if(y2 > y1) return false; + std::swap(y1, y2); + std::swap(rise1, rise2); + } else { return false; } + if(rise1 == 1) { + if(rise2 == 0) { + crossPoint = Point(currentX + y2 - y1, y2); + } else { + //rise2 == -1 + Unit delta = (y2 - y1)/2; + crossPoint = Point(currentX + delta, y1 + delta); + } + } else { + //rise1 == 0 and rise2 == -1 + crossPoint = Point(currentX + y2 - y1, y1); + } + return true; + } + }; + + typedef Scan45ElementT<Count2> Scan45Element; + + // inline std::ostream& operator<< (std::ostream& o, const Scan45Element& c) { + // o << c.x << " " << c.y << " " << c.rise << " " << c.count; + // return o; + // } + + class lessScan45ElementRise : public std::binary_function<Scan45Element, Scan45Element, bool> { + public: + inline lessScan45ElementRise() {} //default constructor is only constructor + inline bool operator () (Scan45Element elm1, Scan45Element elm2) const { + return elm1.rise < elm2.rise; + } + }; + + template <typename CountType> + class lessScan45Element { + private: + Unit *x_; //x value at which to apply comparison + int *justBefore_; + public: + inline lessScan45Element() : x_(0), justBefore_(0) {} + inline lessScan45Element(Unit *x, int *justBefore) : x_(x), justBefore_(justBefore) {} + inline lessScan45Element(const lessScan45Element& that) : x_(that.x_), justBefore_(that.justBefore_) {} + inline lessScan45Element& operator=(const lessScan45Element& that) { x_ = that.x_; justBefore_ = that.justBefore_; return *this; } + inline bool operator () (const Scan45ElementT<CountType>& elm1, + const Scan45ElementT<CountType>& elm2) const { + Unit y1 = elm1.evalAtX(*x_); + Unit y2 = elm2.evalAtX(*x_); + if(y1 < y2) return true; + if(y1 == y2) { + //if justBefore is true we invert the result of the comparison of slopes + if(*justBefore_) { + return elm1.rise > elm2.rise; + } else { + return elm1.rise < elm2.rise; + } + } + return false; + } + }; + + template <typename CountType> + class Scan45CountT { + public: + inline Scan45CountT() : counts() {} //counts[0] = counts[1] = counts[2] = counts[3] = 0; } + inline Scan45CountT(CountType count) : counts() { counts[0] = counts[1] = counts[2] = counts[3] = count; } + inline Scan45CountT(const CountType& count1, const CountType& count2, const CountType& count3, + const CountType& count4) : counts() { + counts[0] = count1; + counts[1] = count2; + counts[2] = count3; + counts[3] = count4; + } + inline Scan45CountT(const Scan45CountT& count) : counts() { + (*this) = count; + } + inline bool operator==(const Scan45CountT& count) const { + for(unsigned int i = 0; i < 4; ++i) { + if(counts[i] != count.counts[i]) return false; + } + return true; + } + inline bool operator!=(const Scan45CountT& count) const { return !((*this) == count); } + inline Scan45CountT& operator=(CountType count) { + counts[0] = counts[1] = counts[2] = counts[3] = count; return *this; } + inline Scan45CountT& operator=(const Scan45CountT& count) { + for(unsigned int i = 0; i < 4; ++i) { + counts[i] = count.counts[i]; + } + return *this; + } + inline CountType& operator[](int index) { return counts[index]; } + inline CountType operator[](int index) const {return counts[index]; } + inline Scan45CountT& operator+=(const Scan45CountT& count){ + for(unsigned int i = 0; i < 4; ++i) { + counts[i] += count.counts[i]; + } + return *this; + } + inline Scan45CountT& operator-=(const Scan45CountT& count){ + for(unsigned int i = 0; i < 4; ++i) { + counts[i] -= count.counts[i]; + } + return *this; + } + inline Scan45CountT operator+(const Scan45CountT& count) const { + return Scan45CountT(*this)+=count; + } + inline Scan45CountT operator-(const Scan45CountT& count) const { + return Scan45CountT(*this)-=count; + } + inline Scan45CountT invert() const { + return Scan45CountT(CountType())-=(*this); + } + inline Scan45CountT& operator+=(const Scan45ElementT<CountType>& element){ + counts[element.rise+1] += element.count; return *this; + } + private: + CountType counts[4]; + }; + + typedef Scan45CountT<Count2> Scan45Count; + + // inline std::ostream& operator<< (std::ostream& o, const Scan45Count& c) { + // o << c[0] << ", " << c[1] << ", "; + // o << c[2] << ", " << c[3]; + // return o; + // } + + + // inline std::ostream& operator<< (std::ostream& o, const Scan45Vertex& c) { + // o << c.first << ": " << c.second; + // return o; + // } + + + //vetex45 is sortable + template <typename ct> + class Vertex45T { + public: + Point pt; + int rise; // 1, 0 or -1 + ct count; //dxdydTheta + inline Vertex45T() : pt(), rise(), count() {} + inline Vertex45T(const Point& point, int riseIn, ct countIn) : pt(point), rise(riseIn), count(countIn) {} + inline Vertex45T(const Vertex45T& vertex) : pt(vertex.pt), rise(vertex.rise), count(vertex.count) {} + inline Vertex45T& operator=(const Vertex45T& vertex){ + pt = vertex.pt; rise = vertex.rise; count = vertex.count; return *this; } + inline Vertex45T(const std::pair<Point, Point>& vertex) : pt(), rise(), count() {} + inline Vertex45T& operator=(const std::pair<Point, Point>& vertex){ return *this; } + inline bool operator==(const Vertex45T& vertex) const { + return pt == vertex.pt && rise == vertex.rise && count == vertex.count; } + inline bool operator!=(const Vertex45T& vertex) const { return !((*this) == vertex); } + inline bool operator==(const std::pair<Point, Point>& vertex) const { return false; } + inline bool operator!=(const std::pair<Point, Point>& vertex) const { return !((*this) == vertex); } + inline bool operator<(const Vertex45T& vertex) const { + if(pt.x() < vertex.pt.x()) return true; + if(pt.x() == vertex.pt.x()) { + if(pt.y() < vertex.pt.y()) return true; + if(pt.y() == vertex.pt.y()) { return rise < vertex.rise; } + } + return false; + } + inline bool operator>(const Vertex45T& vertex) const { return vertex < (*this); } + inline bool operator<=(const Vertex45T& vertex) const { return !((*this) > vertex); } + inline bool operator>=(const Vertex45T& vertex) const { return !((*this) < vertex); } + inline Unit evalAtX(Unit xIn) const { return pt.y() + rise * (xIn - pt.x()); } + }; + + typedef Vertex45T<int> Vertex45; + + // inline std::ostream& operator<< (std::ostream& o, const Vertex45& c) { + // o << c.pt << " " << c.rise << " " << c.count; + // return o; + // } + + //when scanning Vertex45 for polygon formation we need a scanline comparator functor + class lessVertex45 { + private: + Unit *x_; //x value at which to apply comparison + int *justBefore_; + public: + inline lessVertex45() : x_(0), justBefore_() {} + + inline lessVertex45(Unit *x, int *justBefore) : x_(x), justBefore_(justBefore) {} + + inline lessVertex45(const lessVertex45& that) : x_(that.x_), justBefore_(that.justBefore_) {} + + inline lessVertex45& operator=(const lessVertex45& that) { x_ = that.x_; justBefore_ = that.justBefore_; return *this; } + + template <typename ct> + inline bool operator () (const Vertex45T<ct>& elm1, const Vertex45T<ct>& elm2) const { + Unit y1 = elm1.evalAtX(*x_); + Unit y2 = elm2.evalAtX(*x_); + if(y1 < y2) return true; + if(y1 == y2) { + //if justBefore is true we invert the result of the comparison of slopes + if(*justBefore_) { + return elm1.rise > elm2.rise; + } else { + return elm1.rise < elm2.rise; + } + } + return false; + } + }; + + // 0 right to left + // 1 upper right to lower left + // 2 high to low + // 3 upper left to lower right + // 4 left to right + // 5 lower left to upper right + // 6 low to high + // 7 lower right to upper left + static inline int classifyEdge45(const Point& prevPt, const Point& nextPt) { + if(prevPt.x() == nextPt.x()) { + //2 or 6 + return predicated_value(prevPt.y() < nextPt.y(), 6, 2); + } + if(prevPt.y() == nextPt.y()) { + //0 or 4 + return predicated_value(prevPt.x() < nextPt.x(), 4, 0); + } + if(prevPt.x() < nextPt.x()) { + //3 or 5 + return predicated_value(prevPt.y() < nextPt.y(), 5, 3); + } + //prevPt.x() > nextPt.y() + //1 or 7 + return predicated_value(prevPt.y() < nextPt.y(), 7, 1); + } + + template <int op, typename CountType> + static int applyLogic(CountType count1, CountType count2){ + bool l1 = applyLogic<op>(count1); + bool l2 = applyLogic<op>(count2); + if(l1 && !l2) + return -1; //was true before and became false like a trailing edge + if(!l1 && l2) + return 1; //was false before and became true like a leading edge + return 0; //no change in logic between the two counts + } + template <int op> + static bool applyLogic(Count2 count) { +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op == 0) { //apply or + return count[0] > 0 || count[1] > 0; + } else if(op == 1) { //apply and + return count[0] > 0 && count[1] > 0; + } else if(op == 2) { //apply not + return count[0] > 0 && !(count[1] > 0); + } else if(op == 3) { //apply xor + return (count[0] > 0) ^ (count[1] > 0); + } else + return false; +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + } + + template <int op> + struct boolean_op_45_output_functor { + template <typename cT> + void operator()(cT& output, const Count2& count1, const Count2& count2, + const Point& pt, int rise, direction_1d end) { + int edgeType = applyLogic<op>(count1, count2); + if(edgeType) { + int multiplier = end == LOW ? -1 : 1; + //std::cout << "cross logic: " << edgeType << std::endl; + output.insert(output.end(), Vertex45(pt, rise, edgeType * multiplier)); + //std::cout << "write out: " << crossPoint << " " << Point(eraseItrs[i]->x, eraseItrs[i]->y) << std::endl; + } + } + }; + + template <int op> + static bool applyLogic(Count1 count) { +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op == 0) { //apply or + return count.count_ > 0; + } else if(op == 1) { //apply and + return count.count_ > 1; + } else if(op == 3) { //apply xor + return (count.count_ % 2) != 0; + } else + return false; +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + } + + template <int op> + struct unary_op_45_output_functor { + template <typename cT> + void operator()(cT& output, const Count1& count1, const Count1& count2, + const Point& pt, int rise, direction_1d end) { + int edgeType = applyLogic<op>(count1, count2); + if(edgeType) { + int multiplier = end == LOW ? -1 : 1; + //std::cout << "cross logic: " << edgeType << std::endl; + output.insert(output.end(), Vertex45(pt, rise, edgeType * multiplier)); + //std::cout << "write out: " << crossPoint << " " << Point(eraseItrs[i]->x, eraseItrs[i]->y) << std::endl; + } + } + }; + + class lessScan45Vertex { + public: + inline lessScan45Vertex() {} //default constructor is only constructor + template <typename Scan45Vertex> + inline bool operator () (const Scan45Vertex& v1, const Scan45Vertex& v2) const { + return (v1.first.x() < v2.first.x()) || (v1.first.x() == v2.first.x() && v1.first.y() < v2.first.y()); + } + }; + template <typename S45V> + static inline void sortScan45Vector(S45V& vec) { + gtlsort(vec.begin(), vec.end(), lessScan45Vertex()); + } + + template <typename CountType, typename output_functor> + class Scan45 { + public: + typedef Scan45CountT<CountType> Scan45Count; + typedef std::pair<Point, Scan45Count> Scan45Vertex; + + //index is the index into the vertex + static inline Scan45Element getElement(const Scan45Vertex& vertex, int index) { + return Scan45Element(vertex.first.x(), vertex.first.y(), index - 1, vertex.second[index]); + } + + class lessScan45Point : public std::binary_function<Point, Point, bool> { + public: + inline lessScan45Point() {} //default constructor is only constructor + inline bool operator () (const Point& v1, const Point& v2) const { + return (v1.x() < v2.x()) || (v1.x() == v2.x() && v1.y() < v2.y()); + } + }; + + typedef std::vector<Scan45Vertex> Scan45Vector; + + //definitions + typedef std::set<Scan45ElementT<CountType>, lessScan45Element<CountType> > Scan45Data; + typedef typename Scan45Data::iterator iterator; + typedef typename Scan45Data::const_iterator const_iterator; + typedef std::set<Point, lessScan45Point> CrossQueue; + + //data + Scan45Data scanData_; + CrossQueue crossQueue_; + Scan45Vector crossVector_; + Unit x_; + int justBefore_; + public: + inline Scan45() : scanData_(), crossQueue_(), crossVector_(), + x_((std::numeric_limits<Unit>::min)()), justBefore_(false) { + lessScan45Element<CountType> lessElm(&x_, &justBefore_); + scanData_ = std::set<Scan45ElementT<CountType>, lessScan45Element<CountType> >(lessElm); + } + inline Scan45(const Scan45& that) : scanData_(), crossQueue_(), crossVector_(), + x_((std::numeric_limits<Unit>::min)()), justBefore_(false) { + (*this) = that; } + inline Scan45& operator=(const Scan45& that) { + x_ = that.x_; + justBefore_ = that.justBefore_; + crossQueue_ = that.crossQueue_; + crossVector_ = that.crossVector_; + lessScan45Element<CountType> lessElm(&x_, &justBefore_); + scanData_ = std::set<Scan45ElementT<CountType>, lessScan45Element<CountType> >(lessElm); + for(const_iterator itr = that.scanData_.begin(); itr != that.scanData_.end(); ++itr){ + scanData_.insert(scanData_.end(), *itr); + } + return *this; + } + + //cT is an output container of Vertex45 + //iT is an iterator over Scan45Vertex elements + template <class cT, class iT> + void scan(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "1\n"; + while(inputBegin != inputEnd) { + //std::cout << "2\n"; + //std::cout << "x_ = " << x_ << std::endl; + //std::cout << "scan line size: " << scanData_.size() << std::endl; + //for(iterator iter = scanData_.begin(); + // iter != scanData_.end(); ++iter) { + // std::cout << "scan element\n"; + // std::cout << *iter << " " << iter->evalAtX(x_) << std::endl; + // } + // std::cout << "cross queue size: " << crossQueue_.size() << std::endl; + // std::cout << "cross vector size: " << crossVector_.size() << std::endl; + //for(CrossQueue::iterator cqitr = crossQueue_.begin(); cqitr != crossQueue_.end(); ++cqitr) { + // std::cout << *cqitr << " "; + //} std::cout << std::endl; + Unit nextX = (*inputBegin).first.x(); + if(!crossVector_.empty() && crossVector_[0].first.x() < nextX) nextX = crossVector_[0].first.x(); + if(nextX != x_) { + //std::cout << "3\n"; + //we need to move to the next scanline stop + //we need to process end events then cross events + //process end events + if(!crossQueue_.empty() && + (*crossQueue_.begin()).x() < nextX) { + //std::cout << "4\n"; + nextX = (std::min)(nextX, (*crossQueue_.begin()).x()); + } + //std::cout << "6\n"; + justBefore_ = true; + x_ = nextX; + advance_(output); + justBefore_ = false; + if(!crossVector_.empty() && + nextX == (*inputBegin).first.x()) { + inputBegin = mergeCross_(inputBegin, inputEnd); + } + processEvent_(output, crossVector_.begin(), crossVector_.end()); + crossVector_.clear(); + } else { + //std::cout << "7\n"; + //our scanline has progressed to the event that is next in the queue + inputBegin = processEvent_(output, inputBegin, inputEnd); + } + } + //std::cout << "done scanning\n"; + } + + private: + //functions + + template <class cT> + inline void advance_(cT& output) { + //process all cross points on the cross queue at the current x_ + //std::cout << "advance_\n"; + std::vector<iterator> eraseVec; + while(!crossQueue_.empty() && + (*crossQueue_.begin()).x() == x_){ + //std::cout << "loop\n"; + //pop point off the cross queue + Point crossPoint = *(crossQueue_.begin()); + //std::cout << crossPoint << std::endl; + //for(iterator iter = scanData_.begin(); + // iter != scanData_.end(); ++iter) { + // std::cout << "scan element\n"; + // std::cout << *iter << " " << iter->evalAtX(x_) << std::endl; + //} + crossQueue_.erase(crossQueue_.begin()); + Scan45Vertex vertex(crossPoint, Scan45Count()); + iterator lowIter = lookUp_(vertex.first.y()); + //std::cout << "searching at: " << vertex.first.y() << std::endl; + //if(lowIter == scanData_.end()) std::cout << "could not find\n"; + //else std::cout << "found: " << *lowIter << std::endl; + if(lowIter == scanData_.end() || + lowIter->evalAtX(x_) != vertex.first.y()) { + // std::cout << "skipping\n"; + //there weren't any edges at this potential cross point + continue; + } + CountType countBelow; + iterator searchDownItr = lowIter; + while(searchDownItr != scanData_.begin() + && searchDownItr->evalAtX(x_) == vertex.first.y()) { + //get count from below + --searchDownItr; + countBelow = searchDownItr->count; + } + //std::cout << "Below Count: " << countBelow << std::endl; + Scan45Count count(countBelow); + std::size_t numEdges = 0; + iterator eraseItrs[3]; + while(lowIter != scanData_.end() && + lowIter->evalAtX(x_) == vertex.first.y()) { + for(int index = lowIter->rise +1; index >= 0; --index) + count[index] = lowIter->count; + //std::cout << count << std::endl; + eraseItrs[numEdges] = lowIter; + ++numEdges; + ++lowIter; + } + if(numEdges == 1) { + //look for the next crossing point and continue + //std::cout << "found only one edge\n"; + findCross_(eraseItrs[0]); + continue; + } + //before we erase the elements we need to decide if they should be written out + CountType currentCount = countBelow; + for(std::size_t i = 0; i < numEdges; ++i) { + output_functor f; + f(output, currentCount, eraseItrs[i]->count, crossPoint, eraseItrs[i]->rise, LOW); + currentCount = eraseItrs[i]->count; + } + //schedule erase of the elements + for(std::size_t i = 0; i < numEdges; ++i) { + eraseVec.push_back(eraseItrs[i]); + } + + //take the derivative wrt theta of the count at the crossing point + vertex.second[2] = count[2] - countBelow; + vertex.second[1] = count[1] - count[2]; + vertex.second[0] = count[0] - count[1]; + //add the point, deriviative pair into the cross vector + //std::cout << "LOOK HERE!\n"; + //std::cout << count << std::endl; + //std::cout << vertex << std::endl; + crossVector_.push_back(vertex); + } + //erase crossing elements + std::vector<iterator> searchVec; + for(std::size_t i = 0; i < eraseVec.size(); ++i) { + if(eraseVec[i] != scanData_.begin()) { + iterator searchItr = eraseVec[i]; + --searchItr; + if(searchVec.empty() || + searchVec.back() != searchItr) + searchVec.push_back(searchItr); + } + scanData_.erase(eraseVec[i]); + } + for(std::size_t i = 0; i < searchVec.size(); ++i) { + findCross_(searchVec[i]); + } + } + + template <class iT> + inline iT mergeCross_(iT inputBegin, iT inputEnd) { + Scan45Vector vec; + swap(vec, crossVector_); + iT mergeEnd = inputBegin; + std::size_t mergeCount = 0; + while(mergeEnd != inputEnd && + (*mergeEnd).first.x() == x_) { + ++mergeCount; + ++mergeEnd; + } + crossVector_.reserve((std::max)(vec.capacity(), vec.size() + mergeCount)); + for(std::size_t i = 0; i < vec.size(); ++i){ + while(inputBegin != mergeEnd && + (*inputBegin).first.y() < vec[i].first.y()) { + crossVector_.push_back(*inputBegin); + ++inputBegin; + } + crossVector_.push_back(vec[i]); + } + while(inputBegin != mergeEnd){ + crossVector_.push_back(*inputBegin); + ++inputBegin; + } + return inputBegin; + } + + template <class cT, class iT> + inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "processEvent_\n"; + CountType verticalCount = CountType(); + Point prevPoint; + iterator prevIter = scanData_.end(); + while(inputBegin != inputEnd && + (*inputBegin).first.x() == x_) { + //std::cout << (*inputBegin) << std::endl; + //std::cout << "loop\n"; + Scan45Vertex vertex = *inputBegin; + //std::cout << vertex.first << std::endl; + //if vertical count propigating up fake a null event at the next element + if(verticalCount != CountType() && (prevIter != scanData_.end() && + prevIter->evalAtX(x_) < vertex.first.y())) { + //std::cout << "faking null event\n"; + vertex = Scan45Vertex(Point(x_, prevIter->evalAtX(x_)), Scan45Count()); + } else { + ++inputBegin; + //std::cout << "after increment\n"; + //accumulate overlapping changes in Scan45Count + while(inputBegin != inputEnd && + (*inputBegin).first.x() == x_ && + (*inputBegin).first.y() == vertex.first.y()) { + //std::cout << "accumulate\n"; + vertex.second += (*inputBegin).second; + ++inputBegin; + } + } + //std::cout << vertex.second << std::endl; + //integrate vertex + CountType currentCount = verticalCount;// + vertex.second[0]; + for(unsigned int i = 0; i < 3; ++i) { + vertex.second[i] = currentCount += vertex.second[i]; + } + //std::cout << vertex.second << std::endl; + //vertex represents the change in state at this point + + //get counts at current vertex + CountType countBelow; + iterator lowIter = lookUp_(vertex.first.y()); + if(lowIter != scanData_.begin()) { + //get count from below + --lowIter; + countBelow = lowIter->count; + ++lowIter; + } + //std::cout << "Count Below: " << countBelow[0] << " " << countBelow[1] << std::endl; + //std::cout << "vertical count: " << verticalCount[0] << " " << verticalCount[1] << std::endl; + Scan45Count countAt(countBelow - verticalCount); + //check if the vertical edge should be written out + if(verticalCount != CountType()) { + output_functor f; + f(output, countBelow - verticalCount, countBelow, prevPoint, 2, HIGH); + f(output, countBelow - verticalCount, countBelow, vertex.first, 2, LOW); + } + currentCount = countBelow - verticalCount; + while(lowIter != scanData_.end() && + lowIter->evalAtX(x_) == vertex.first.y()) { + for(unsigned int i = lowIter->rise + 1; i < 3; ++i) { + countAt[i] = lowIter->count; + } + Point lp(lowIter->x, lowIter->y); + if(lp != vertex.first) { + output_functor f; + f(output, currentCount, lowIter->count, vertex.first, lowIter->rise, LOW); + } + currentCount = lowIter->count; + iterator nextIter = lowIter; + ++nextIter; + //std::cout << "erase\n"; + scanData_.erase(lowIter); + if(nextIter != scanData_.end()) + findCross_(nextIter); + lowIter = nextIter; + } + verticalCount += vertex.second[3]; + prevPoint = vertex.first; + //std::cout << "new vertical count: " << verticalCount[0] << " " << verticalCount[1] << std::endl; + prevIter = lowIter; + //count represents the current state at this point + //std::cout << vertex.second << std::endl; + //std::cout << countAt << std::endl; + //std::cout << "ADD\n"; + vertex.second += countAt; + //std::cout << vertex.second << std::endl; + + //add elements to the scanline + for(int i = 0; i < 3; ++i) { + if(vertex.second[i] != countBelow) { + //std::cout << "insert: " << vertex.first.x() << " " << vertex.first.y() << " " << i-1 << + // " " << vertex.second[i][0] << " " << vertex.second[i][1] << std::endl; + iterator insertIter = scanData_.insert(scanData_.end(), + Scan45ElementT<CountType>(vertex.first.x(), + vertex.first.y(), + i - 1, vertex.second[i])); + findCross_(insertIter); + output_functor f; + f(output, countBelow, vertex.second[i], vertex.first, i - 1, HIGH); + } + countBelow = vertex.second[i]; + } + } + //std::cout << "end processEvent\n"; + return inputBegin; + } + + //iter1 is horizontal + inline void scheduleCross0_(iterator iter1, iterator iter2) { + //std::cout << "0, "; + Unit y1 = iter1->evalAtX(x_); + Unit y2 = iter2->evalAtX(x_); + LongUnit delta = local_abs(LongUnit(y1) - LongUnit(y2)); + if(delta + static_cast<LongUnit>(x_) <= (std::numeric_limits<Unit>::max)()) + crossQueue_.insert(crossQueue_.end(), Point(x_ + static_cast<Unit>(delta), y1)); + //std::cout << Point(x_ + delta, y1); + } + + //neither iter is horizontal + inline void scheduleCross1_(iterator iter1, iterator iter2) { + //std::cout << "1, "; + Unit y1 = iter1->evalAtX(x_); + Unit y2 = iter2->evalAtX(x_); + //std::cout << y1 << " " << y2 << ": "; + //note that half the delta cannot exceed the positive inter range + LongUnit delta = y1; + delta -= y2; + Unit UnitMax = (std::numeric_limits<Unit>::max)(); + if((delta & 1) == 1) { + //delta is odd, division by 2 will result in integer trunctaion + if(delta == 1) { + //the cross point is not on the integer grid and cannot be represented + //we must throw an exception + std::string msg = "GTL 45 Boolean error, precision insufficient to represent edge intersection coordinate value."; + throw(msg); + } else { + //note that result of this subtraction is always positive because itr1 is above itr2 in scanline + LongUnit halfDelta2 = (LongUnit)((((LongUnit)y1) - y2)/2); + //note that halfDelta2 has been truncated + if(halfDelta2 + x_ <= UnitMax && halfDelta2 + y2 <= UnitMax) { + crossQueue_.insert(crossQueue_.end(), Point(x_+static_cast<Unit>(halfDelta2), y2+static_cast<Unit>(halfDelta2))); + crossQueue_.insert(crossQueue_.end(), Point(x_+static_cast<Unit>(halfDelta2), y2+static_cast<Unit>(halfDelta2)+1)); + } + } + } else { + LongUnit halfDelta = (LongUnit)((((LongUnit)y1) - y2)/2); + if(halfDelta + x_ <= UnitMax && halfDelta + y2 <= UnitMax) + crossQueue_.insert(crossQueue_.end(), Point(x_+static_cast<Unit>(halfDelta), y2+static_cast<Unit>(halfDelta))); + //std::cout << Point(x_+halfDelta, y2+halfDelta); + } + } + + inline void findCross_(iterator iter) { + //std::cout << "find cross "; + iterator iteratorBelow = iter; + iterator iteratorAbove = iter; + if(iter != scanData_.begin() && iter->rise < 1) { + --iteratorBelow; + if(iter->rise == 0){ + if(iteratorBelow->rise == 1) { + scheduleCross0_(iter, iteratorBelow); + } + } else { + //iter->rise == -1 + if(iteratorBelow->rise == 1) { + scheduleCross1_(iter, iteratorBelow); + } else if(iteratorBelow->rise == 0) { + scheduleCross0_(iteratorBelow, iter); + } + } + } + ++iteratorAbove; + if(iteratorAbove != scanData_.end() && iter->rise > -1) { + if(iter->rise == 0) { + if(iteratorAbove->rise == -1) { + scheduleCross0_(iter, iteratorAbove); + } + } else { + //iter->rise == 1 + if(iteratorAbove->rise == -1) { + scheduleCross1_(iteratorAbove, iter); + } else if(iteratorAbove->rise == 0) { + scheduleCross0_(iteratorAbove, iter); + } + } + } + //std::cout << std::endl; + } + + inline iterator lookUp_(Unit y){ + //if just before then we need to look from 1 not -1 + return scanData_.lower_bound(Scan45ElementT<CountType>(x_, y, -1+2*justBefore_)); + } + }; + + //template <typename CountType> + //static inline void print45Data(const std::set<Scan45ElementT<CountType>, + // lessScan45Element<CountType> >& data) { + // typename std::set<Scan45ElementT<CountType>, lessScan45Element<CountType> >::const_iterator iter; + // for(iter = data.begin(); iter != data.end(); ++iter) { + // std::cout << iter->x << " " << iter->y << " " << iter->rise << std::endl; + // } + //} + + template <typename streamtype> + static inline bool testScan45Data(streamtype& stdcout) { + Unit x = 0; + int justBefore = false; + lessScan45Element<Count2> lessElm(&x, &justBefore); + std::set<Scan45ElementT<Count2>, lessScan45Element<Count2> > testData(lessElm); + //Unit size = testData.size(); + typedef std::set<Scan45ElementT<Count2>, lessScan45Element<Count2> > Scan45Data; + typename Scan45Data::iterator itr10 = testData.insert(testData.end(), Scan45Element(0, 10, 1)); + typename Scan45Data::iterator itr20 = testData.insert(testData.end(), Scan45Element(0, 20, 1)); + typename Scan45Data::iterator itr30 = testData.insert(testData.end(), Scan45Element(0, 30, -1)); + typename Scan45Data::iterator itr40 = testData.insert(testData.end(), Scan45Element(0, 40, -1)); + typename Scan45Data::iterator itrA = testData.lower_bound(Scan45Element(0, 29, -1)); + typename Scan45Data::iterator itr1 = testData.lower_bound(Scan45Element(0, 10, -1)); + x = 4; + //now at 14 24 26 36 + typename Scan45Data::iterator itrB = testData.lower_bound(Scan45Element(4, 29, -1)); + typename Scan45Data::iterator itr2 = testData.lower_bound(Scan45Element(4, 14, -1)); + if(itr1 != itr2) stdcout << "test1 failed\n"; + if(itrA == itrB) stdcout << "test2 failed\n"; + //remove crossing elements + testData.erase(itr20); + testData.erase(itr30); + x = 5; + itr20 = testData.insert(testData.end(), Scan45Element(0, 20, 1)); + itr30 = testData.insert(testData.end(), Scan45Element(0, 30, -1)); + //now at 15 25 25 35 + typename Scan45Data::iterator itr = testData.begin(); + if(itr != itr10) stdcout << "test3 failed\n"; + ++itr; + if(itr != itr30) stdcout << "test4 failed\n"; + ++itr; + if(itr != itr20) stdcout << "test5 failed\n"; + ++itr; + if(itr != itr40) stdcout << "test6 failed\n"; + stdcout << "done testing Scan45Data\n"; + return true; + } + + template <typename stream_type> + static inline bool testScan45Rect(stream_type& stdcout) { + stdcout << "testing Scan45Rect\n"; + Scan45<Count2, boolean_op_45_output_functor<0> > scan45; + std::vector<Vertex45 > result; + typedef std::pair<Point, Scan45Count> Scan45Vertex; + std::vector<Scan45Vertex> vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,0), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + vertices.push_back(Scan45Vertex(Point(0,10), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(10,0), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(10,10), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + // result size == 8 + // result == 0 0 0 1 + // result == 0 0 2 1 + // result == 0 10 2 -1 + // result == 0 10 0 -1 + // result == 10 0 0 -1 + // result == 10 0 2 -1 + // result == 10 10 2 1 + // result == 10 10 0 1 + std::vector<Vertex45> reference; + reference.push_back(Vertex45(Point(0, 0), 0, 1)); + reference.push_back(Vertex45(Point(0, 0), 2, 1)); + reference.push_back(Vertex45(Point(0, 10), 2, -1)); + reference.push_back(Vertex45(Point(0, 10), 0, -1)); + reference.push_back(Vertex45(Point(10, 0), 0, -1)); + reference.push_back(Vertex45(Point(10, 0), 2, -1)); + reference.push_back(Vertex45(Point(10, 10), 2, 1)); + reference.push_back(Vertex45(Point(10, 10), 0, 1)); + if(result != reference) { + stdcout << "result size == " << result.size() << std::endl; + for(std::size_t i = 0; i < result.size(); ++i) { + //std::cout << "result == " << result[i]<< std::endl; + } + stdcout << "reference size == " << reference.size() << std::endl; + for(std::size_t i = 0; i < reference.size(); ++i) { + //std::cout << "reference == " << reference[i]<< std::endl; + } + return false; + } + stdcout << "done testing Scan45Rect\n"; + return true; + } + + template <typename stream_type> + static inline bool testScan45P1(stream_type& stdcout) { + stdcout << "testing Scan45P1\n"; + Scan45<Count2, boolean_op_45_output_functor<0> > scan45; + std::vector<Vertex45 > result; + typedef std::pair<Point, Scan45Count> Scan45Vertex; + std::vector<Scan45Vertex> vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,0), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); + vertices.push_back(Scan45Vertex(Point(0,10), Scan45Count(Count2(0, 0), Count2(0, 0), ncount, ncount))); + vertices.push_back(Scan45Vertex(Point(10,10), Scan45Count(Count2(0, 0), Count2(0, 0), ncount, ncount))); + vertices.push_back(Scan45Vertex(Point(10,20), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + // result size == 8 + // result == 0 0 1 1 + // result == 0 0 2 1 + // result == 0 10 2 -1 + // result == 0 10 1 -1 + // result == 10 10 1 -1 + // result == 10 10 2 -1 + // result == 10 20 2 1 + // result == 10 20 1 1 + std::vector<Vertex45> reference; + reference.push_back(Vertex45(Point(0, 0), 1, 1)); + reference.push_back(Vertex45(Point(0, 0), 2, 1)); + reference.push_back(Vertex45(Point(0, 10), 2, -1)); + reference.push_back(Vertex45(Point(0, 10), 1, -1)); + reference.push_back(Vertex45(Point(10, 10), 1, -1)); + reference.push_back(Vertex45(Point(10, 10), 2, -1)); + reference.push_back(Vertex45(Point(10, 20), 2, 1)); + reference.push_back(Vertex45(Point(10, 20), 1, 1)); + if(result != reference) { + stdcout << "result size == " << result.size() << std::endl; + for(std::size_t i = 0; i < result.size(); ++i) { + //std::cout << "result == " << result[i]<< std::endl; + } + stdcout << "reference size == " << reference.size() << std::endl; + for(std::size_t i = 0; i < reference.size(); ++i) { + //std::cout << "reference == " << reference[i]<< std::endl; + } + return false; + } + stdcout << "done testing Scan45P1\n"; + return true; + } + + template <typename stream_type> + static inline bool testScan45P2(stream_type& stdcout) { + stdcout << "testing Scan45P2\n"; + Scan45<Count2, boolean_op_45_output_functor<0> > scan45; + std::vector<Vertex45 > result; + typedef std::pair<Point, Scan45Count> Scan45Vertex; + std::vector<Scan45Vertex> vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,0), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(10,0), Scan45Count(Count2(0, 0), ncount, count, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(10,10), Scan45Count(Count2(0, 0), ncount, count, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(20,10), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + // result size == 8 + // result == 0 0 0 1 + // result == 0 0 1 -1 + // result == 10 0 0 -1 + // result == 10 0 1 1 + // result == 10 10 1 1 + // result == 10 10 0 -1 + // result == 20 10 1 -1 + // result == 20 10 0 1 + std::vector<Vertex45> reference; + reference.push_back(Vertex45(Point(0, 0), 0, 1)); + reference.push_back(Vertex45(Point(0, 0), 1, -1)); + reference.push_back(Vertex45(Point(10, 0), 0, -1)); + reference.push_back(Vertex45(Point(10, 0), 1, 1)); + reference.push_back(Vertex45(Point(10, 10), 1, 1)); + reference.push_back(Vertex45(Point(10, 10), 0, -1)); + reference.push_back(Vertex45(Point(20, 10), 1, -1)); + reference.push_back(Vertex45(Point(20, 10), 0, 1)); + if(result != reference) { + stdcout << "result size == " << result.size() << std::endl; + for(std::size_t i = 0; i < result.size(); ++i) { + //stdcout << "result == " << result[i]<< std::endl; + } + stdcout << "reference size == " << reference.size() << std::endl; + for(std::size_t i = 0; i < reference.size(); ++i) { + //stdcout << "reference == " << reference[i]<< std::endl; + } + return false; + } + stdcout << "done testing Scan45P2\n"; + return true; + } + + template <typename streamtype> + static inline bool testScan45And(streamtype& stdcout) { + stdcout << "testing Scan45And\n"; + Scan45<Count2, boolean_op_45_output_functor<1> > scan45; + std::vector<Vertex45 > result; + typedef std::pair<Point, Scan45Count> Scan45Vertex; + std::vector<Scan45Vertex> vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,0), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + vertices.push_back(Scan45Vertex(Point(0,10), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(10,0), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(10,10), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + count = Count2(0, 1); + ncount = count.invert(); + vertices.push_back(Scan45Vertex(Point(2,2), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + vertices.push_back(Scan45Vertex(Point(2,12), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(12,2), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(12,12), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + sortScan45Vector(vertices); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + //result size == 8 + //result == 2 2 0 1 + //result == 2 2 2 1 + //result == 2 10 2 -1 + //result == 2 10 0 -1 + //result == 10 2 0 -1 + //result == 10 2 2 -1 + //result == 10 10 2 1 + //result == 10 10 0 1 + std::vector<Vertex45> reference; + reference.push_back(Vertex45(Point(2, 2), 0, 1)); + reference.push_back(Vertex45(Point(2, 2), 2, 1)); + reference.push_back(Vertex45(Point(2, 10), 2, -1)); + reference.push_back(Vertex45(Point(2, 10), 0, -1)); + reference.push_back(Vertex45(Point(10, 2), 0, -1)); + reference.push_back(Vertex45(Point(10, 2), 2, -1)); + reference.push_back(Vertex45(Point(10, 10), 2, 1)); + reference.push_back(Vertex45(Point(10, 10), 0, 1)); + if(result != reference) { + stdcout << "result size == " << result.size() << std::endl; + for(std::size_t i = 0; i < result.size(); ++i) { + //stdcout << "result == " << result[i]<< std::endl; + } + stdcout << "reference size == " << reference.size() << std::endl; + for(std::size_t i = 0; i < reference.size(); ++i) { + //stdcout << "reference == " << reference[i]<< std::endl; + } + return false; + } + stdcout << "done testing Scan45And\n"; + return true; + } + + template <typename stream_type> + static inline bool testScan45Star1(stream_type& stdcout) { + stdcout << "testing Scan45Star1\n"; + Scan45<Count2, boolean_op_45_output_functor<0> > scan45; + std::vector<Vertex45 > result; + typedef std::pair<Point, Scan45Count> Scan45Vertex; + std::vector<Scan45Vertex> vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, Count2(0, 0), ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(8,16), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); + count = Count2(0, 1); + ncount = count.invert(); + vertices.push_back(Scan45Vertex(Point(12,8), Scan45Count(count, Count2(0, 0), ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(4,0), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); + vertices.push_back(Scan45Vertex(Point(4,16), Scan45Count(ncount, Count2(0, 0), Count2(0, 0), ncount))); + sortScan45Vector(vertices); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + // result size == 24 + // result == 0 8 -1 1 + // result == 0 8 1 -1 + // result == 4 0 1 1 + // result == 4 0 2 1 + // result == 4 4 2 -1 + // result == 4 4 -1 -1 + // result == 4 12 1 1 + // result == 4 12 2 1 + // result == 4 16 2 -1 + // result == 4 16 -1 -1 + // result == 6 2 1 -1 + // result == 6 14 -1 1 + // result == 6 2 -1 1 + // result == 6 14 1 -1 + // result == 8 0 -1 -1 + // result == 8 0 2 -1 + // result == 8 4 2 1 + // result == 8 4 1 1 + // result == 8 12 -1 -1 + // result == 8 12 2 -1 + // result == 8 16 2 1 + // result == 8 16 1 1 + // result == 12 8 1 -1 + // result == 12 8 -1 1 + if(result.size() != 24) { + //stdcout << "result size == " << result.size() << std::endl; + //stdcout << "reference size == " << 24 << std::endl; + return false; + } + stdcout << "done testing Scan45Star1\n"; + return true; + } + + template <typename stream_type> + static inline bool testScan45Star2(stream_type& stdcout) { + stdcout << "testing Scan45Star2\n"; + Scan45<Count2, boolean_op_45_output_functor<0> > scan45; + std::vector<Vertex45 > result; + typedef std::pair<Point, Scan45Count> Scan45Vertex; + std::vector<Scan45Vertex> vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,4), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,4), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,12), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + count = Count2(0, 1); + ncount = count.invert(); + vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,8), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + sortScan45Vector(vertices); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + // result size == 24 + // result == 0 4 0 1 + // result == 0 4 1 -1 + // result == 0 8 -1 1 + // result == 0 8 0 -1 + // result == 2 6 1 1 + // result == 2 6 -1 -1 + // result == 4 4 0 -1 + // result == 4 8 0 1 + // result == 4 4 -1 1 + // result == 4 8 1 -1 + // result == 8 0 -1 -1 + // result == 8 0 1 1 + // result == 8 12 1 1 + // result == 8 12 -1 -1 + // result == 12 4 1 -1 + // result == 12 8 -1 1 + // result == 12 4 0 1 + // result == 12 8 0 -1 + // result == 14 6 -1 -1 + // result == 14 6 1 1 + // result == 16 4 0 -1 + // result == 16 4 -1 1 + // result == 16 8 1 -1 + // result == 16 8 0 1 + if(result.size() != 24) { + //std::cout << "result size == " << result.size() << std::endl; + //std::cout << "reference size == " << 24 << std::endl; + return false; + } + stdcout << "done testing Scan45Star2\n"; + return true; + } + + template <typename stream_type> + static inline bool testScan45Star3(stream_type& stdcout) { + stdcout << "testing Scan45Star3\n"; + Scan45<Count2, boolean_op_45_output_functor<0> > scan45; + std::vector<Vertex45 > result; + typedef std::pair<Point, Scan45Count> Scan45Vertex; + std::vector<Scan45Vertex> vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, Count2(0, 0), ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(8,16), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); + + vertices.push_back(Scan45Vertex(Point(6,0), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + vertices.push_back(Scan45Vertex(Point(6,14), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(12,0), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(12,14), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + count = Count2(0, 1); + ncount = count.invert(); + vertices.push_back(Scan45Vertex(Point(12,8), Scan45Count(count, Count2(0, 0), ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(4,0), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); + vertices.push_back(Scan45Vertex(Point(4,16), Scan45Count(ncount, Count2(0, 0), Count2(0, 0), ncount))); + sortScan45Vector(vertices); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + // result size == 28 + // result == 0 8 -1 1 + // result == 0 8 1 -1 + // result == 4 0 1 1 + // result == 4 0 2 1 + // result == 4 4 2 -1 + // result == 4 4 -1 -1 + // result == 4 12 1 1 + // result == 4 12 2 1 + // result == 4 16 2 -1 + // result == 4 16 -1 -1 + // result == 6 2 1 -1 + // result == 6 14 -1 1 + // result == 6 0 0 1 + // result == 6 0 2 1 + // result == 6 2 2 -1 + // result == 6 14 1 -1 + // result == 8 0 0 -1 + // result == 8 0 0 1 + // result == 8 14 0 -1 + // result == 8 14 2 -1 + // result == 8 16 2 1 + // result == 8 16 1 1 + // result == 12 0 0 -1 + // result == 12 0 2 -1 + // result == 12 8 2 1 + // result == 12 8 2 -1 + // result == 12 14 2 1 + // result == 12 14 0 1 + if(result.size() != 28) { + //std::cout << "result size == " << result.size() << std::endl; + //std::cout << "reference size == " << 28 << std::endl; + return false; + } + + stdcout << "done testing Scan45Star3\n"; + return true; + } + + + template <typename stream_type> + static inline bool testScan45Star4(stream_type& stdcout) { + stdcout << "testing Scan45Star4\n"; + Scan45<Count2, boolean_op_45_output_functor<0> > scan45; + std::vector<Vertex45 > result; + typedef std::pair<Point, Scan45Count> Scan45Vertex; + std::vector<Scan45Vertex> vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,4), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,4), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,12), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + + vertices.push_back(Scan45Vertex(Point(0,6), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + vertices.push_back(Scan45Vertex(Point(0,12), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(16,6), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(16,12), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + count = Count2(0, 1); + ncount = count.invert(); + vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,8), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + sortScan45Vector(vertices); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + // result size == 28 + // result == 0 4 0 1 + // result == 0 4 1 -1 + // result == 0 6 0 1 + // result == 0 6 2 1 + // result == 0 8 2 -1 + // result == 0 8 2 1 + // result == 0 12 2 -1 + // result == 0 12 0 -1 + // result == 2 6 1 1 + // result == 2 6 0 -1 + // result == 4 4 0 -1 + // result == 4 4 -1 1 + // result == 8 12 0 1 + // result == 8 0 -1 -1 + // result == 8 0 1 1 + // result == 8 12 0 -1 + // result == 12 4 1 -1 + // result == 12 4 0 1 + // result == 14 6 -1 -1 + // result == 14 6 0 1 + // result == 16 4 0 -1 + // result == 16 4 -1 1 + // result == 16 6 0 -1 + // result == 16 6 2 -1 + // result == 16 8 2 1 + // result == 16 8 2 -1 + // result == 16 12 2 1 + // result == 16 12 0 1 + if(result.size() != 28) { + //stdcout << "result size == " << result.size() << std::endl; + //stdcout << "reference size == " << 28 << std::endl; + return false; + } + + stdcout << "done testing Scan45Star4\n"; + return true; + } + + template <typename stream_type> + static inline bool testScan45(stream_type& stdcout) { + if(!testScan45Rect(stdcout)) return false; + if(!testScan45P1(stdcout)) return false; + if(!testScan45P2(stdcout)) return false; + if(!testScan45And(stdcout)) return false; + if(!testScan45Star1(stdcout)) return false; + if(!testScan45Star2(stdcout)) return false; + if(!testScan45Star3(stdcout)) return false; + if(!testScan45Star4(stdcout)) return false; + return true; + } + + }; + +} + +} +#endif diff --git a/boost/polygon/detail/iterator_compact_to_points.hpp b/boost/polygon/detail/iterator_compact_to_points.hpp new file mode 100644 index 0000000000..9634e6f75e --- /dev/null +++ b/boost/polygon/detail/iterator_compact_to_points.hpp @@ -0,0 +1,69 @@ +/* + 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_ITERATOR_COMPACT_TO_POINTS_HPP +#define BOOST_POLYGON_ITERATOR_COMPACT_TO_POINTS_HPP +namespace boost { namespace polygon{ +template <typename iterator_type, typename point_type> +class iterator_compact_to_points { +private: + iterator_type iter_; + iterator_type iter_end_; + point_type pt_; + typename point_traits<point_type>::coordinate_type firstX_; + orientation_2d orient_; +public: + typedef std::forward_iterator_tag iterator_category; + typedef point_type value_type; + typedef std::ptrdiff_t difference_type; + typedef const point_type* pointer; //immutable + typedef const point_type& reference; //immutable + + inline iterator_compact_to_points() : iter_(), iter_end_(), pt_(), firstX_(), orient_() {} + inline iterator_compact_to_points(iterator_type iter, iterator_type iter_end) : + iter_(iter), iter_end_(iter_end), pt_(), firstX_(), orient_(HORIZONTAL) { + if(iter_ != iter_end_) { + firstX_ = *iter_; + x(pt_, firstX_); + ++iter_; + if(iter_ != iter_end_) { + y(pt_, *iter_); + } + } + } + //use bitwise copy and assign provided by the compiler + inline iterator_compact_to_points& operator++() { + iterator_type prev_iter = iter_; + ++iter_; + if(iter_ == iter_end_) { + if(x(pt_) != firstX_) { + iter_ = prev_iter; + x(pt_, firstX_); + } + } else { + set(pt_, orient_, *iter_); + orient_.turn_90(); + } + return *this; + } + inline const iterator_compact_to_points operator++(int) { + iterator_compact_to_points tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator_compact_to_points& that) const { + return (iter_ == that.iter_); + } + inline bool operator!=(const iterator_compact_to_points& that) const { + return (iter_ != that.iter_); + } + inline reference operator*() const { return pt_; } +}; +} +} +#endif + diff --git a/boost/polygon/detail/iterator_geometry_to_set.hpp b/boost/polygon/detail/iterator_geometry_to_set.hpp new file mode 100644 index 0000000000..4f6287309a --- /dev/null +++ b/boost/polygon/detail/iterator_geometry_to_set.hpp @@ -0,0 +1,315 @@ +/* + 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_ITERATOR_GEOMETRY_TO_SET_HPP +#define BOOST_POLYGON_ITERATOR_GEOMETRY_TO_SET_HPP +namespace boost { namespace polygon{ +template <typename concept_type, typename geometry_type> +class iterator_geometry_to_set {}; + +template <typename rectangle_type> +class iterator_geometry_to_set<rectangle_concept, rectangle_type> { +public: + typedef typename rectangle_traits<rectangle_type>::coordinate_type coordinate_type; + typedef std::forward_iterator_tag iterator_category; + typedef std::pair<coordinate_type, std::pair<coordinate_type, int> > value_type; + typedef std::ptrdiff_t difference_type; + typedef const value_type* pointer; //immutable + typedef const value_type& reference; //immutable +private: + rectangle_data<coordinate_type> rectangle_; + mutable value_type vertex_; + unsigned int corner_; + orientation_2d orient_; + bool is_hole_; +public: + iterator_geometry_to_set() : rectangle_(), vertex_(), corner_(4), orient_(), is_hole_() {} + iterator_geometry_to_set(const rectangle_type& rectangle, direction_1d dir, + orientation_2d orient = HORIZONTAL, bool is_hole = false, bool = false, direction_1d = CLOCKWISE) : + rectangle_(), vertex_(), corner_(0), orient_(orient), is_hole_(is_hole) { + assign(rectangle_, rectangle); + if(dir == HIGH) corner_ = 4; + } + inline iterator_geometry_to_set& operator++() { + ++corner_; + return *this; + } + inline const iterator_geometry_to_set operator++(int) { + iterator_geometry_to_set tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator_geometry_to_set& that) const { + return corner_ == that.corner_; + } + inline bool operator!=(const iterator_geometry_to_set& that) const { + return !(*this == that); + } + inline reference operator*() const { + if(corner_ == 0) { + vertex_.first = get(get(rectangle_, orient_.get_perpendicular()), LOW); + vertex_.second.first = get(get(rectangle_, orient_), LOW); + vertex_.second.second = 1; + if(is_hole_) vertex_.second.second *= -1; + } else if(corner_ == 1) { + vertex_.second.first = get(get(rectangle_, orient_), HIGH); + vertex_.second.second = -1; + if(is_hole_) vertex_.second.second *= -1; + } else if(corner_ == 2) { + vertex_.first = get(get(rectangle_, orient_.get_perpendicular()), HIGH); + vertex_.second.first = get(get(rectangle_, orient_), LOW); + } else { + vertex_.second.first = get(get(rectangle_, orient_), HIGH); + vertex_.second.second = 1; + if(is_hole_) vertex_.second.second *= -1; + } + return vertex_; + } +}; + +template <typename polygon_type> +class iterator_geometry_to_set<polygon_90_concept, polygon_type> { +public: + typedef typename polygon_traits<polygon_type>::coordinate_type coordinate_type; + typedef std::forward_iterator_tag iterator_category; + typedef std::pair<coordinate_type, std::pair<coordinate_type, int> > value_type; + typedef std::ptrdiff_t difference_type; + typedef const value_type* pointer; //immutable + typedef const value_type& reference; //immutable + typedef typename polygon_traits<polygon_type>::iterator_type coord_iterator_type; +private: + value_type vertex_; + typename polygon_traits<polygon_type>::iterator_type itrb, itre; + bool last_vertex_; + bool is_hole_; + int multiplier_; + point_data<coordinate_type> first_pt, second_pt, pts[3]; + bool use_wrap; + orientation_2d orient_; + int polygon_index; +public: + iterator_geometry_to_set() : vertex_(), itrb(), itre(), last_vertex_(), is_hole_(), multiplier_(), first_pt(), second_pt(), pts(), use_wrap(), orient_(), polygon_index(-1) {} + iterator_geometry_to_set(const polygon_type& polygon, direction_1d dir, orientation_2d orient = HORIZONTAL, bool is_hole = false, bool winding_override = false, direction_1d w = CLOCKWISE) : + vertex_(), itrb(), itre(), last_vertex_(), + is_hole_(is_hole), multiplier_(), first_pt(), second_pt(), pts(), use_wrap(), + orient_(orient), polygon_index(0) { + itrb = begin_points(polygon); + itre = end_points(polygon); + use_wrap = false; + if(itrb == itre || dir == HIGH || size(polygon) < 4) { + polygon_index = -1; + } else { + direction_1d wdir = w; + if(!winding_override) + wdir = winding(polygon); + multiplier_ = wdir == LOW ? -1 : 1; + if(is_hole_) multiplier_ *= -1; + first_pt = pts[0] = *itrb; + ++itrb; + second_pt = pts[1] = *itrb; + ++itrb; + pts[2] = *itrb; + evaluate_(); + } + } + iterator_geometry_to_set(const iterator_geometry_to_set& that) : + vertex_(), itrb(), itre(), last_vertex_(), is_hole_(), multiplier_(), first_pt(), + second_pt(), pts(), use_wrap(), orient_(), polygon_index(-1) { + vertex_ = that.vertex_; + itrb = that.itrb; + itre = that.itre; + last_vertex_ = that.last_vertex_; + is_hole_ = that.is_hole_; + multiplier_ = that.multiplier_; + first_pt = that.first_pt; + second_pt = that.second_pt; + pts[0] = that.pts[0]; + pts[1] = that.pts[1]; + pts[2] = that.pts[2]; + use_wrap = that.use_wrap; + orient_ = that.orient_; + polygon_index = that.polygon_index; + } + inline iterator_geometry_to_set& operator++() { + ++polygon_index; + if(itrb == itre) { + if(first_pt == pts[1]) polygon_index = -1; + else { + pts[0] = pts[1]; + pts[1] = pts[2]; + if(first_pt == pts[2]) { + pts[2] = second_pt; + } else { + pts[2] = first_pt; + } + } + } else { + ++itrb; + pts[0] = pts[1]; + pts[1] = pts[2]; + if(itrb == itre) { + if(first_pt == pts[2]) { + pts[2] = second_pt; + } else { + pts[2] = first_pt; + } + } else { + pts[2] = *itrb; + } + } + evaluate_(); + return *this; + } + inline const iterator_geometry_to_set operator++(int) { + iterator_geometry_to_set tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator_geometry_to_set& that) const { + return polygon_index == that.polygon_index; + } + inline bool operator!=(const iterator_geometry_to_set& that) const { + return !(*this == that); + } + inline reference operator*() const { + return vertex_; + } + + inline void evaluate_() { + vertex_.first = pts[1].get(orient_.get_perpendicular()); + vertex_.second.first =pts[1].get(orient_); + if(pts[1] == pts[2]) { + vertex_.second.second = 0; + } else if(pts[0].get(HORIZONTAL) != pts[1].get(HORIZONTAL)) { + vertex_.second.second = -1; + } else if(pts[0].get(VERTICAL) != pts[1].get(VERTICAL)) { + vertex_.second.second = 1; + } else { + vertex_.second.second = 0; + } + vertex_.second.second *= multiplier_; + } +}; + +template <typename polygon_with_holes_type> +class iterator_geometry_to_set<polygon_90_with_holes_concept, polygon_with_holes_type> { +public: + typedef typename polygon_90_traits<polygon_with_holes_type>::coordinate_type coordinate_type; + typedef std::forward_iterator_tag iterator_category; + typedef std::pair<coordinate_type, std::pair<coordinate_type, int> > value_type; + typedef std::ptrdiff_t difference_type; + typedef const value_type* pointer; //immutable + typedef const value_type& reference; //immutable +private: + iterator_geometry_to_set<polygon_90_concept, polygon_with_holes_type> itrb, itre; + iterator_geometry_to_set<polygon_90_concept, typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type> itrhib, itrhie; + typename polygon_with_holes_traits<polygon_with_holes_type>::iterator_holes_type itrhb, itrhe; + orientation_2d orient_; + bool is_hole_; + bool started_holes; +public: + iterator_geometry_to_set() : itrb(), itre(), itrhib(), itrhie(), itrhb(), itrhe(), orient_(), is_hole_(), started_holes() {} + iterator_geometry_to_set(const polygon_with_holes_type& polygon, direction_1d dir, + orientation_2d orient = HORIZONTAL, bool is_hole = false, bool = false, direction_1d = CLOCKWISE) : + itrb(), itre(), itrhib(), itrhie(), itrhb(), itrhe(), orient_(orient), is_hole_(is_hole), started_holes() { + itre = iterator_geometry_to_set<polygon_90_concept, polygon_with_holes_type>(polygon, HIGH, orient, is_hole_); + itrhe = end_holes(polygon); + if(dir == HIGH) { + itrb = itre; + itrhb = itrhe; + started_holes = true; + } else { + itrb = iterator_geometry_to_set<polygon_90_concept, polygon_with_holes_type>(polygon, LOW, orient, is_hole_); + itrhb = begin_holes(polygon); + started_holes = false; + } + } + iterator_geometry_to_set(const iterator_geometry_to_set& that) : + itrb(), itre(), itrhib(), itrhie(), itrhb(), itrhe(), orient_(), is_hole_(), started_holes() { + itrb = that.itrb; + itre = that.itre; + if(that.itrhib != that.itrhie) { + itrhib = that.itrhib; + itrhie = that.itrhie; + } + itrhb = that.itrhb; + itrhe = that.itrhe; + orient_ = that.orient_; + is_hole_ = that.is_hole_; + started_holes = that.started_holes; + } + inline iterator_geometry_to_set& operator++() { + //this code can be folded with flow control factoring + if(itrb == itre) { + if(itrhib == itrhie) { + if(itrhb != itrhe) { + itrhib = iterator_geometry_to_set<polygon_90_concept, + typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(*itrhb, LOW, orient_, !is_hole_); + itrhie = iterator_geometry_to_set<polygon_90_concept, + typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(*itrhb, HIGH, orient_, !is_hole_); + ++itrhb; + } else { + //in this case we have no holes so we just need the iterhib == itrhie, which + //is always true if they were default initialized in the initial case or + //both point to end of the previous hole processed + //no need to explicitly reset them, and it causes an stl debug assertion to use + //the default constructed iterator this way + //itrhib = itrhie = iterator_geometry_to_set<polygon_90_concept, + // typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(); + } + } else { + ++itrhib; + if(itrhib == itrhie) { + if(itrhb != itrhe) { + itrhib = iterator_geometry_to_set<polygon_90_concept, + typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(*itrhb, LOW, orient_, !is_hole_); + itrhie = iterator_geometry_to_set<polygon_90_concept, + typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(*itrhb, HIGH, orient_, !is_hole_); + ++itrhb; + } else { + //this is the same case as above + //itrhib = itrhie = iterator_geometry_to_set<polygon_90_concept, + // typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(); + } + } + } + } else { + ++itrb; + if(itrb == itre) { + if(itrhb != itrhe) { + itrhib = iterator_geometry_to_set<polygon_90_concept, + typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(*itrhb, LOW, orient_, !is_hole_); + itrhie = iterator_geometry_to_set<polygon_90_concept, + typename polygon_with_holes_traits<polygon_with_holes_type>::hole_type>(*itrhb, HIGH, orient_, !is_hole_); + ++itrhb; + } + } + } + return *this; + } + inline const iterator_geometry_to_set operator++(int) { + iterator_geometry_to_set tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator_geometry_to_set& that) const { + return itrb == that.itrb && itrhb == that.itrhb && itrhib == that.itrhib; + } + inline bool operator!=(const iterator_geometry_to_set& that) const { + return !(*this == that); + } + inline reference operator*() const { + if(itrb != itre) return *itrb; + return *itrhib; + } +}; + + +} +} +#endif + diff --git a/boost/polygon/detail/iterator_points_to_compact.hpp b/boost/polygon/detail/iterator_points_to_compact.hpp new file mode 100644 index 0000000000..25ddb15889 --- /dev/null +++ b/boost/polygon/detail/iterator_points_to_compact.hpp @@ -0,0 +1,60 @@ +/* + 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_ITERATOR_POINTS_TO_COMPACT_HPP +#define BOOST_POLYGON_ITERATOR_POINTS_TO_COMPACT_HPP +namespace boost { namespace polygon{ +template <typename iT, typename point_type> +class iterator_points_to_compact { +private: + iT iter_, iterEnd_; + orientation_2d orient_; + mutable typename point_traits<point_type>::coordinate_type coord_; +public: + typedef typename point_traits<point_type>::coordinate_type coordinate_type; + typedef std::forward_iterator_tag iterator_category; + typedef coordinate_type value_type; + typedef std::ptrdiff_t difference_type; + typedef const coordinate_type* pointer; //immutable + typedef const coordinate_type& reference; //immutable + + inline iterator_points_to_compact() : iter_(), iterEnd_(), orient_(), coord_() {} + inline iterator_points_to_compact(iT iter, iT iterEnd) : + iter_(iter), iterEnd_(iterEnd), orient_(HORIZONTAL), coord_() {} + inline iterator_points_to_compact(const iterator_points_to_compact& that) : + iter_(that.iter_), iterEnd_(that.iterEnd_), orient_(that.orient_), coord_(that.coord_) {} + //use bitwise copy and assign provided by the compiler + inline iterator_points_to_compact& operator++() { + //iT tmp = iter_; + ++iter_; + //iT tmp2 = iter_; + orient_.turn_90(); + //while(tmp2 != iterEnd_ && get(*tmp2, orient_) == get(*tmp, orient_)) { + // iter_ = tmp2; + // ++tmp2; + //} + return *this; + } + inline const iterator_points_to_compact operator++(int) { + iT tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator_points_to_compact& that) const { + return (iter_ == that.iter_); + } + inline bool operator!=(const iterator_points_to_compact& that) const { + return (iter_ != that.iter_); + } + inline reference operator*() const { coord_ = get(*iter_, orient_); + return coord_; + } +}; +} +} +#endif + diff --git a/boost/polygon/detail/max_cover.hpp b/boost/polygon/detail/max_cover.hpp new file mode 100644 index 0000000000..343e29a795 --- /dev/null +++ b/boost/polygon/detail/max_cover.hpp @@ -0,0 +1,278 @@ +/* + 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_MAX_COVER_HPP +#define BOOST_POLYGON_MAX_COVER_HPP +namespace boost { namespace polygon{ + + template <typename Unit> + struct MaxCover { + typedef interval_data<Unit> Interval; + typedef rectangle_data<Unit> Rectangle; + + class Node { + private: + std::vector<Node*> children_; + std::set<Interval> tracedPaths_; + public: + Rectangle rect; + Node() : children_(), tracedPaths_(), rect() {} + Node(const Rectangle rectIn) : children_(), tracedPaths_(), rect(rectIn) {} + typedef typename std::vector<Node*>::iterator iterator; + inline iterator begin() { return children_.begin(); } + inline iterator end() { return children_.end(); } + inline void add(Node* child) { children_.push_back(child); } + inline bool tracedPath(const Interval& ivl) const { + return tracedPaths_.find(ivl) != tracedPaths_.end(); + } + inline void addPath(const Interval& ivl) { + tracedPaths_.insert(tracedPaths_.end(), ivl); + } + }; + + typedef std::pair<std::pair<Unit, Interval>, Node* > EdgeAssociation; + + class lessEdgeAssociation : public std::binary_function<const EdgeAssociation&, const EdgeAssociation&, bool> { + public: + inline lessEdgeAssociation() {} + inline bool operator () (const EdgeAssociation& elem1, const EdgeAssociation& elem2) const { + if(elem1.first.first < elem2.first.first) return true; + if(elem1.first.first > elem2.first.first) return false; + return elem1.first.second < elem2.first.second; + } + }; + + template <class cT> + static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient) { + Interval rectIvl = node->rect.get(orient); + if(node->tracedPath(rectIvl)) { + return; + } + node->addPath(rectIvl); + if(node->begin() == node->end()) { + //std::cout << "WRITE OUT 3: " << node->rect << std::endl; + outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(node->rect)); + return; + } + bool writeOut = true; + for(typename Node::iterator itr = node->begin(); itr != node->end(); ++itr) { + getMaxCover(outputContainer, *itr, orient, node->rect); //get rectangles down path + Interval nodeIvl = (*itr)->rect.get(orient); + if(contains(nodeIvl, rectIvl, true)) writeOut = false; + } + if(writeOut) { + //std::cout << "WRITE OUT 2: " << node->rect << std::endl; + outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(node->rect)); + } + } + + struct stack_element { + inline stack_element() : + node(), rect(), itr() {} + inline stack_element(Node* n, + const Rectangle& r, + typename Node::iterator i) : + node(n), rect(r), itr(i) {} + Node* node; + Rectangle rect; + typename Node::iterator itr; + }; + + template <class cT> + static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient, + Rectangle rect) { + //std::cout << "New Root\n"; + std::vector<stack_element> stack; + typename Node::iterator itr = node->begin(); + do { + //std::cout << "LOOP\n"; + //std::cout << node->rect << std::endl; + Interval rectIvl = rect.get(orient); + Interval nodeIvl = node->rect.get(orient); + bool iresult = intersect(rectIvl, nodeIvl, false); + bool tresult = !node->tracedPath(rectIvl); + //std::cout << (itr != node->end()) << " " << iresult << " " << tresult << std::endl; + Rectangle nextRect1 = Rectangle(rectIvl, rectIvl); + Unit low = rect.get(orient.get_perpendicular()).low(); + Unit high = node->rect.get(orient.get_perpendicular()).high(); + nextRect1.set(orient.get_perpendicular(), Interval(low, high)); + if(iresult && tresult) { + node->addPath(rectIvl); + bool writeOut = true; + //check further visibility beyond this node + for(typename Node::iterator itr2 = node->begin(); itr2 != node->end(); ++itr2) { + Interval nodeIvl3 = (*itr2)->rect.get(orient); + //if a child of this node can contain the interval then we can extend through + if(contains(nodeIvl3, rectIvl, true)) writeOut = false; + //std::cout << "child " << (*itr2)->rect << std::endl; + } + Rectangle nextRect2 = Rectangle(rectIvl, rectIvl); + Unit low2 = rect.get(orient.get_perpendicular()).low(); + Unit high2 = node->rect.get(orient.get_perpendicular()).high(); + nextRect2.set(orient.get_perpendicular(), Interval(low2, high2)); + if(writeOut) { + //std::cout << "write out " << nextRect << std::endl; + outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(nextRect2)); + } else { + //std::cout << "supress " << nextRect << std::endl; + } + } + if(itr != node->end() && iresult && tresult) { + //std::cout << "recurse into child\n"; + stack.push_back(stack_element(node, rect, itr)); + rect = nextRect1; + node = *itr; + itr = node->begin(); + } else { + if(!stack.empty()) { + //std::cout << "recurse out of child\n"; + node = stack.back().node; + rect = stack.back().rect; + itr = stack.back().itr; + stack.pop_back(); + } else { + //std::cout << "empty stack\n"; + //if there were no children of the root node +// Rectangle nextRect = Rectangle(rectIvl, rectIvl); +// Unit low = rect.get(orient.get_perpendicular()).low(); +// Unit high = node->rect.get(orient.get_perpendicular()).high(); +// nextRect.set(orient.get_perpendicular(), Interval(low, high)); +// outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(nextRect)); + } + //std::cout << "increment " << (itr != node->end()) << std::endl; + if(itr != node->end()) { + ++itr; + if(itr != node->end()) { + //std::cout << "recurse into next child.\n"; + stack.push_back(stack_element(node, rect, itr)); + Interval rectIvl2 = rect.get(orient); + Interval nodeIvl2 = node->rect.get(orient); + /*bool iresult =*/ intersect(rectIvl2, nodeIvl2, false); + Rectangle nextRect2 = Rectangle(rectIvl2, rectIvl2); + Unit low2 = rect.get(orient.get_perpendicular()).low(); + Unit high2 = node->rect.get(orient.get_perpendicular()).high(); + nextRect2.set(orient.get_perpendicular(), Interval(low2, high2)); + rect = nextRect2; + //std::cout << "rect for next child" << rect << std::endl; + node = *itr; + itr = node->begin(); + } + } + } + } while(!stack.empty() || itr != node->end()); + } + + /* Function recursive version of getMaxCover + Because the code is so much simpler than the loop algorithm I retain it for clarity + + template <class cT> + static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient, + const Rectangle& rect) { + Interval rectIvl = rect.get(orient); + Interval nodeIvl = node->rect.get(orient); + if(!intersect(rectIvl, nodeIvl, false)) { + return; + } + if(node->tracedPath(rectIvl)) { + return; + } + node->addPath(rectIvl); + Rectangle nextRect(rectIvl, rectIvl); + Unit low = rect.get(orient.get_perpendicular()).low(); + Unit high = node->rect.get(orient.get_perpendicular()).high(); + nextRect.set(orient.get_perpendicular(), Interval(low, high)); + bool writeOut = true; + rectIvl = nextRect.get(orient); + for(typename Node::iterator itr = node->begin(); itr != node->end(); ++itr) { + nodeIvl = (*itr)->rect.get(orient); + if(contains(nodeIvl, rectIvl, true)) writeOut = false; + } + if(writeOut) { + outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(nextRect)); + } + for(typename Node::iterator itr = node->begin(); itr != node->end(); ++itr) { + getMaxCover(outputContainer, *itr, orient, nextRect); + } + } + */ + + //iterator range is assummed to be in topological order meaning all node's trailing + //edges are in sorted order + template <class iT> + static inline void computeDag(iT beginNode, iT endNode, orientation_2d orient, + std::size_t size) { + std::vector<EdgeAssociation> leadingEdges; + leadingEdges.reserve(size); + for(iT iter = beginNode; iter != endNode; ++iter) { + Node* nodep = &(*iter); + Unit leading = nodep->rect.get(orient.get_perpendicular()).low(); + Interval rectIvl = nodep->rect.get(orient); + leadingEdges.push_back(EdgeAssociation(std::pair<Unit, Interval>(leading, rectIvl), nodep)); + } + gtlsort(leadingEdges.begin(), leadingEdges.end(), lessEdgeAssociation()); + typename std::vector<EdgeAssociation>::iterator leadingBegin = leadingEdges.begin(); + iT trailingBegin = beginNode; + while(leadingBegin != leadingEdges.end()) { + EdgeAssociation& leadingSegment = (*leadingBegin); + Unit trailing = (*trailingBegin).rect.get(orient.get_perpendicular()).high(); + Interval ivl = (*trailingBegin).rect.get(orient); + std::pair<Unit, Interval> trailingSegment(trailing, ivl); + if(leadingSegment.first.first < trailingSegment.first) { + ++leadingBegin; + continue; + } + if(leadingSegment.first.first > trailingSegment.first) { + ++trailingBegin; + continue; + } + if(leadingSegment.first.second.high() <= trailingSegment.second.low()) { + ++leadingBegin; + continue; + } + if(trailingSegment.second.high() <= leadingSegment.first.second.low()) { + ++trailingBegin; + continue; + } + //leading segment intersects trailing segment + (*trailingBegin).add((*leadingBegin).second); + if(leadingSegment.first.second.high() > trailingSegment.second.high()) { + ++trailingBegin; + continue; + } + if(trailingSegment.second.high() > leadingSegment.first.second.high()) { + ++leadingBegin; + continue; + } + ++leadingBegin; + ++trailingBegin; + } + } + + template <class cT> + static inline void getMaxCover(cT& outputContainer, + const std::vector<Rectangle>& rects, orientation_2d orient) { + if(rects.empty()) return; + std::vector<Node> nodes; + { + if(rects.size() == 1) { + outputContainer.push_back(copy_construct<typename cT::value_type, Rectangle>(rects[0])); + return; + } + nodes.reserve(rects.size()); + for(std::size_t i = 0; i < rects.size(); ++i) { nodes.push_back(Node(rects[i])); } + } + computeDag(nodes.begin(), nodes.end(), orient, nodes.size()); + for(std::size_t i = 0; i < nodes.size(); ++i) { + getMaxCover(outputContainer, &(nodes[i]), orient); + } + } + + }; +} +} + +#endif diff --git a/boost/polygon/detail/minkowski.hpp b/boost/polygon/detail/minkowski.hpp new file mode 100644 index 0000000000..312d9a284d --- /dev/null +++ b/boost/polygon/detail/minkowski.hpp @@ -0,0 +1,125 @@ + +namespace boost { namespace polygon { namespace detail { + +template <typename coordinate_type> +struct minkowski_offset { + typedef point_data<coordinate_type> point; + typedef polygon_set_data<coordinate_type> polygon_set; + typedef polygon_with_holes_data<coordinate_type> polygon; + typedef std::pair<point, point> edge; + + static void convolve_two_segments(std::vector<point>& figure, const edge& a, const edge& b) { + figure.clear(); + figure.push_back(point(a.first)); + figure.push_back(point(a.first)); + figure.push_back(point(a.second)); + figure.push_back(point(a.second)); + convolve(figure[0], b.second); + convolve(figure[1], b.first); + convolve(figure[2], b.first); + convolve(figure[3], b.second); + } + + template <typename itrT1, typename itrT2> + static void convolve_two_point_sequences(polygon_set& result, itrT1 ab, itrT1 ae, itrT2 bb, itrT2 be) { + if(ab == ae || bb == be) + return; + point first_a = *ab; + point prev_a = *ab; + std::vector<point> vec; + polygon poly; + ++ab; + for( ; ab != ae; ++ab) { + point first_b = *bb; + point prev_b = *bb; + itrT2 tmpb = bb; + ++tmpb; + for( ; tmpb != be; ++tmpb) { + convolve_two_segments(vec, std::make_pair(prev_b, *tmpb), std::make_pair(prev_a, *ab)); + set_points(poly, vec.begin(), vec.end()); + result.insert(poly); + prev_b = *tmpb; + } + prev_a = *ab; + } + } + + template <typename itrT> + static void convolve_point_sequence_with_polygons(polygon_set& result, itrT b, itrT e, const std::vector<polygon>& polygons) { + for(std::size_t i = 0; i < polygons.size(); ++i) { + convolve_two_point_sequences(result, b, e, begin_points(polygons[i]), end_points(polygons[i])); + for(typename polygon_with_holes_traits<polygon>::iterator_holes_type itrh = begin_holes(polygons[i]); + itrh != end_holes(polygons[i]); ++itrh) { + convolve_two_point_sequences(result, b, e, begin_points(*itrh), end_points(*itrh)); + } + } + } + + static void convolve_two_polygon_sets(polygon_set& result, const polygon_set& a, const polygon_set& b) { + result.clear(); + std::vector<polygon> a_polygons; + std::vector<polygon> b_polygons; + a.get(a_polygons); + b.get(b_polygons); + for(std::size_t ai = 0; ai < a_polygons.size(); ++ai) { + convolve_point_sequence_with_polygons(result, begin_points(a_polygons[ai]), + end_points(a_polygons[ai]), b_polygons); + for(typename polygon_with_holes_traits<polygon>::iterator_holes_type itrh = begin_holes(a_polygons[ai]); + itrh != end_holes(a_polygons[ai]); ++itrh) { + convolve_point_sequence_with_polygons(result, begin_points(*itrh), + end_points(*itrh), b_polygons); + } + for(std::size_t bi = 0; bi < b_polygons.size(); ++bi) { + polygon tmp_poly = a_polygons[ai]; + result.insert(convolve(tmp_poly, *(begin_points(b_polygons[bi])))); + tmp_poly = b_polygons[bi]; + result.insert(convolve(tmp_poly, *(begin_points(a_polygons[ai])))); + } + } + } +}; + +} + template<typename T> + inline polygon_set_data<T>& + polygon_set_data<T>::resize(coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments) { + using namespace ::boost::polygon::operators; + if(!corner_fill_arc) { + if(resizing < 0) + return shrink(-resizing); + if(resizing > 0) + return bloat(resizing); + return *this; + } + if(resizing == 0) return *this; + if(empty()) return *this; + if(num_circle_segments < 3) num_circle_segments = 4; + rectangle_data<coordinate_type> rect; + extents(rect); + if(resizing < 0) { + ::boost::polygon::bloat(rect, 10); + (*this) = rect - (*this); //invert + } + //make_arc(std::vector<point_data< T> >& return_points, + //point_data< double> start, point_data< double> end, + //point_data< double> center, double r, unsigned int num_circle_segments) + std::vector<point_data<coordinate_type> > circle; + point_data<double> center(0.0, 0.0), start(0.0, (double)resizing); + make_arc(circle, start, start, center, std::abs((double)resizing), + num_circle_segments); + polygon_data<coordinate_type> poly; + set_points(poly, circle.begin(), circle.end()); + polygon_set_data<coordinate_type> offset_set; + offset_set += poly; + polygon_set_data<coordinate_type> result; + detail::minkowski_offset<coordinate_type>::convolve_two_polygon_sets + (result, *this, offset_set); + if(resizing < 0) { + result = result & rect;//eliminate overhang + result = result ^ rect;//invert + } + *this = result; + return *this; + } + +}} diff --git a/boost/polygon/detail/polygon_45_formation.hpp b/boost/polygon/detail/polygon_45_formation.hpp new file mode 100644 index 0000000000..e814a1584f --- /dev/null +++ b/boost/polygon/detail/polygon_45_formation.hpp @@ -0,0 +1,2255 @@ +/* + 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_POLYGON_45_FORMATION_HPP +#define BOOST_POLYGON_POLYGON_45_FORMATION_HPP +namespace boost { namespace polygon{ + + template <typename T, typename T2> + struct PolyLineByConcept {}; + + template <typename T> + class PolyLine45PolygonData; + template <typename T> + class PolyLine45HoleData; + + //polygon45formation algorithm + template <typename Unit> + struct polygon_45_formation : public boolean_op_45<Unit> { + typedef point_data<Unit> Point; + typedef polygon_45_data<Unit> Polygon45; + typedef polygon_45_with_holes_data<Unit> Polygon45WithHoles; + typedef typename boolean_op_45<Unit>::Vertex45 Vertex45; + typedef typename boolean_op_45<Unit>::lessVertex45 lessVertex45; + typedef typename boolean_op_45<Unit>::Count2 Count2; + typedef typename boolean_op_45<Unit>::Scan45Count Scan45Count; + typedef std::pair<Point, Scan45Count> Scan45Vertex; + typedef typename boolean_op_45<Unit>::template + Scan45<Count2, typename boolean_op_45<Unit>::template boolean_op_45_output_functor<0> > Scan45; + + class PolyLine45 { + public: + typedef typename std::list<Point>::const_iterator iterator; + + // default constructor of point does not initialize x and y + inline PolyLine45() : points() {} //do nothing default constructor + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template<class iT> + inline PolyLine45& set(iT inputBegin, iT inputEnd) { + points.clear(); //just in case there was some old data there + while(inputBegin != inputEnd) { + points.insert(points.end(), *inputBegin); + ++inputBegin; + } + return *this; + } + + // copy constructor (since we have dynamic memory) + inline PolyLine45(const PolyLine45& that) : points(that.points) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline PolyLine45& operator=(const PolyLine45& that) { + points = that.points; + return *this; + } + + // get begin iterator, returns a pointer to a const Unit + inline iterator begin() const { return points.begin(); } + + // get end iterator, returns a pointer to a const Unit + inline iterator end() const { return points.end(); } + + inline std::size_t size() const { return points.size(); } + + //public data member + std::list<Point> points; + }; + + class ActiveTail45 { + private: + //data + PolyLine45* tailp_; + ActiveTail45 *otherTailp_; + std::list<ActiveTail45*> holesList_; + bool head_; + public: + + /** + * @brief iterator over coordinates of the figure + */ + typedef typename PolyLine45::iterator iterator; + + /** + * @brief iterator over holes contained within the figure + */ + typedef typename std::list<ActiveTail45*>::const_iterator iteratorHoles; + + //default constructor + inline ActiveTail45() : tailp_(0), otherTailp_(0), holesList_(), head_(0) {} + + //constructor + inline ActiveTail45(const Vertex45& vertex, ActiveTail45* otherTailp = 0) : + tailp_(0), otherTailp_(0), holesList_(), head_(0) { + tailp_ = new PolyLine45; + tailp_->points.push_back(vertex.pt); + bool headArray[4] = {false, true, true, true}; + bool inverted = vertex.count == -1; + head_ = headArray[vertex.rise+1] ^ inverted; + otherTailp_ = otherTailp; + } + + inline ActiveTail45(Point point, ActiveTail45* otherTailp, bool head = true) : + tailp_(0), otherTailp_(0), holesList_(), head_(0) { + tailp_ = new PolyLine45; + tailp_->points.push_back(point); + head_ = head; + otherTailp_ = otherTailp; + + } + inline ActiveTail45(ActiveTail45* otherTailp) : + tailp_(0), otherTailp_(0), holesList_(), head_(0) { + tailp_ = otherTailp->tailp_; + otherTailp_ = otherTailp; + } + + //copy constructor + inline ActiveTail45(const ActiveTail45& that) : + tailp_(0), otherTailp_(0), holesList_(), head_(0) { (*this) = that; } + + //destructor + inline ~ActiveTail45() { + destroyContents(); + } + + //assignment operator + inline ActiveTail45& operator=(const ActiveTail45& that) { + tailp_ = new PolyLine45(*(that.tailp_)); + head_ = that.head_; + otherTailp_ = that.otherTailp_; + holesList_ = that.holesList_; + return *this; + } + + //equivalence operator + inline bool operator==(const ActiveTail45& b) const { + return tailp_ == b.tailp_ && head_ == b.head_; + } + + /** + * @brief get the pointer to the polyline that this is an active tail of + */ + inline PolyLine45* getTail() const { return tailp_; } + + /** + * @brief get the pointer to the polyline at the other end of the chain + */ + inline PolyLine45* getOtherTail() const { return otherTailp_->tailp_; } + + /** + * @brief get the pointer to the activetail at the other end of the chain + */ + inline ActiveTail45* getOtherActiveTail() const { return otherTailp_; } + + /** + * @brief test if another active tail is the other end of the chain + */ + inline bool isOtherTail(const ActiveTail45& b) const { return &b == otherTailp_; } + + /** + * @brief update this end of chain pointer to new polyline + */ + inline ActiveTail45& updateTail(PolyLine45* newTail) { tailp_ = newTail; return *this; } + + inline bool join(ActiveTail45* tail) { + if(tail == otherTailp_) { + //std::cout << "joining to other tail!\n"; + return false; + } + if(tail->head_ == head_) { + //std::cout << "joining head to head!\n"; + return false; + } + if(!tailp_) { + //std::cout << "joining empty tail!\n"; + return false; + } + if(!(otherTailp_->head_)) { + otherTailp_->copyHoles(*tail); + otherTailp_->copyHoles(*this); + } else { + tail->otherTailp_->copyHoles(*this); + tail->otherTailp_->copyHoles(*tail); + } + PolyLine45* tail1 = tailp_; + PolyLine45* tail2 = tail->tailp_; + if(head_) std::swap(tail1, tail2); + tail1->points.splice(tail1->points.end(), tail2->points); + delete tail2; + otherTailp_->tailp_ = tail1; + tail->otherTailp_->tailp_ = tail1; + otherTailp_->otherTailp_ = tail->otherTailp_; + tail->otherTailp_->otherTailp_ = otherTailp_; + tailp_ = 0; + tail->tailp_ = 0; + tail->otherTailp_ = 0; + otherTailp_ = 0; + return true; + } + + /** + * @brief associate a hole to this active tail by the specified policy + */ + inline ActiveTail45* addHole(ActiveTail45* hole) { + holesList_.push_back(hole); + copyHoles(*hole); + copyHoles(*(hole->otherTailp_)); + return this; + } + + /** + * @brief get the list of holes + */ + inline const std::list<ActiveTail45*>& getHoles() const { return holesList_; } + + /** + * @brief copy holes from that to this + */ + inline void copyHoles(ActiveTail45& that) { holesList_.splice(holesList_.end(), that.holesList_); } + + /** + * @brief find out if solid to right + */ + inline bool solidToRight() const { return !head_; } + inline bool solidToLeft() const { return head_; } + + /** + * @brief get vertex + */ + inline Point getPoint() const { + if(head_) return tailp_->points.front(); + return tailp_->points.back(); + } + + /** + * @brief add a coordinate to the polygon at this active tail end, properly handle degenerate edges by removing redundant coordinate + */ + inline void pushPoint(Point point) { + if(head_) { + //if(tailp_->points.size() < 2) { + // tailp_->points.push_front(point); + // return; + //} + typename std::list<Point>::iterator iter = tailp_->points.begin(); + if(iter == tailp_->points.end()) { + tailp_->points.push_front(point); + return; + } + Unit firstY = (*iter).y(); + Unit firstX = (*iter).x(); + ++iter; + if(iter == tailp_->points.end()) { + tailp_->points.push_front(point); + return; + } + if((iter->y() == point.y() && firstY == point.y()) || + (iter->x() == point.x() && firstX == point.x())){ + --iter; + *iter = point; + } else { + tailp_->points.push_front(point); + } + return; + } + //if(tailp_->points.size() < 2) { + // tailp_->points.push_back(point); + // return; + //} + typename std::list<Point>::reverse_iterator iter = tailp_->points.rbegin(); + if(iter == tailp_->points.rend()) { + tailp_->points.push_back(point); + return; + } + Unit firstY = (*iter).y(); + Unit firstX = (*iter).x(); + ++iter; + if(iter == tailp_->points.rend()) { + tailp_->points.push_back(point); + return; + } + if((iter->y() == point.y() && firstY == point.y()) || + (iter->x() == point.x() && firstX == point.x())){ + --iter; + *iter = point; + } else { + tailp_->points.push_back(point); + } + } + + /** + * @brief joins the two chains that the two active tail tails are ends of + * checks for closure of figure and writes out polygons appropriately + * returns a handle to a hole if one is closed + */ + + template <class cT> + static inline ActiveTail45* joinChains(Point point, ActiveTail45* at1, ActiveTail45* at2, bool solid, + cT& output) { + if(at1->otherTailp_ == at2) { + //if(at2->otherTailp_ != at1) std::cout << "half closed error\n"; + //we are closing a figure + at1->pushPoint(point); + at2->pushPoint(point); + if(solid) { + //we are closing a solid figure, write to output + //std::cout << "test1\n"; + at1->copyHoles(*(at1->otherTailp_)); + //std::cout << "test2\n"; + //Polygon45WithHolesImpl<PolyLine45PolygonData> poly(polyData); + //std::cout << poly << std::endl; + //std::cout << "test3\n"; + typedef typename cT::value_type pType; + output.push_back(pType()); + typedef typename geometry_concept<pType>::type cType; + typename PolyLineByConcept<Unit, cType>::type polyData(at1); + assign(output.back(), polyData); + //std::cout << "test4\n"; + //std::cout << "delete " << at1->otherTailp_ << std::endl; + //at1->print(); + //at1->otherTailp_->print(); + delete at1->otherTailp_; + //at1->print(); + //at1->otherTailp_->print(); + //std::cout << "test5\n"; + //std::cout << "delete " << at1 << std::endl; + delete at1; + //std::cout << "test6\n"; + return 0; + } else { + //we are closing a hole, return the tail end active tail of the figure + return at1; + } + } + //we are not closing a figure + at1->pushPoint(point); + at1->join(at2); + delete at1; + delete at2; + return 0; + } + + inline void destroyContents() { + if(otherTailp_) { + //std::cout << "delete p " << tailp_ << std::endl; + if(tailp_) delete tailp_; + tailp_ = 0; + otherTailp_->otherTailp_ = 0; + otherTailp_->tailp_ = 0; + otherTailp_ = 0; + } + for(typename std::list<ActiveTail45*>::iterator itr = holesList_.begin(); itr != holesList_.end(); ++itr) { + //std::cout << "delete p " << (*itr) << std::endl; + if(*itr) { + if((*itr)->otherTailp_) { + delete (*itr)->otherTailp_; + (*itr)->otherTailp_ = 0; + } + delete (*itr); + } + (*itr) = 0; + } + holesList_.clear(); + } + +// inline void print() { +// std::cout << this << " " << tailp_ << " " << otherTailp_ << " " << holesList_.size() << " " << head_ << std::endl; +// } + + static inline std::pair<ActiveTail45*, ActiveTail45*> createActiveTail45sAsPair(Point point, bool solid, + ActiveTail45* phole, bool fractureHoles) { + ActiveTail45* at1 = 0; + ActiveTail45* at2 = 0; + if(phole && fractureHoles) { + //std::cout << "adding hole\n"; + at1 = phole; + //assert solid == false, we should be creating a corner with solid below and to the left if there was a hole + at2 = at1->getOtherActiveTail(); + at2->pushPoint(point); + at1->pushPoint(point); + } else { + at1 = new ActiveTail45(point, at2, solid); + at2 = new ActiveTail45(at1); + at1->otherTailp_ = at2; + at2->head_ = !solid; + if(phole) + at2->addHole(phole); //assert fractureHoles == false + } + return std::pair<ActiveTail45*, ActiveTail45*>(at1, at2); + } + + }; + + template <typename ct> + class Vertex45CountT { + public: + typedef ct count_type; + inline Vertex45CountT() +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { counts[0] = counts[1] = counts[2] = counts[3] = 0; } + //inline Vertex45CountT(ct count) { counts[0] = counts[1] = counts[2] = counts[3] = count; } + inline Vertex45CountT(const ct& count1, const ct& count2, const ct& count3, + const ct& count4) +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { + counts[0] = count1; + counts[1] = count2; + counts[2] = count3; + counts[3] = count4; + } + inline Vertex45CountT(const Vertex45& vertex) +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { + counts[0] = counts[1] = counts[2] = counts[3] = 0; + (*this) += vertex; + } + inline Vertex45CountT(const Vertex45CountT& count) +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { + (*this) = count; + } + inline bool operator==(const Vertex45CountT& count) const { + for(unsigned int i = 0; i < 4; ++i) { + if(counts[i] != count.counts[i]) return false; + } + return true; + } + inline bool operator!=(const Vertex45CountT& count) const { return !((*this) == count); } + inline Vertex45CountT& operator=(ct count) { + counts[0] = counts[1] = counts[2] = counts[3] = count; return *this; } + inline Vertex45CountT& operator=(const Vertex45CountT& count) { + for(unsigned int i = 0; i < 4; ++i) { + counts[i] = count.counts[i]; + } + return *this; + } + inline ct& operator[](int index) { return counts[index]; } + inline ct operator[](int index) const {return counts[index]; } + inline Vertex45CountT& operator+=(const Vertex45CountT& count){ + for(unsigned int i = 0; i < 4; ++i) { + counts[i] += count.counts[i]; + } + return *this; + } + inline Vertex45CountT& operator-=(const Vertex45CountT& count){ + for(unsigned int i = 0; i < 4; ++i) { + counts[i] -= count.counts[i]; + } + return *this; + } + inline Vertex45CountT operator+(const Vertex45CountT& count) const { + return Vertex45CountT(*this)+=count; + } + inline Vertex45CountT operator-(const Vertex45CountT& count) const { + return Vertex45CountT(*this)-=count; + } + inline Vertex45CountT invert() const { + return Vertex45CountT()-=(*this); + } + inline Vertex45CountT& operator+=(const Vertex45& element){ + counts[element.rise+1] += element.count; return *this; + } + inline bool is_45() const { + return counts[0] != 0 || counts[2] != 0; + } + private: + ct counts[4]; + }; + + typedef Vertex45CountT<int> Vertex45Count; + +// inline std::ostream& operator<< (std::ostream& o, const Vertex45Count& c) { +// o << c[0] << ", " << c[1] << ", "; +// o << c[2] << ", " << c[3]; +// return o; +// } + + template <typename ct> + class Vertex45CompactT { + public: + Point pt; + ct count; + typedef typename boolean_op_45<Unit>::template Vertex45T<typename ct::count_type> Vertex45T; + inline Vertex45CompactT() : pt(), count() {} + inline Vertex45CompactT(const Point& point, int riseIn, int countIn) : pt(point), count() { + count[riseIn+1] = countIn; + } + template <typename ct2> + inline Vertex45CompactT(const typename boolean_op_45<Unit>::template Vertex45T<ct2>& vertex) : pt(vertex.pt), count() { + count[vertex.rise+1] = vertex.count; + } + inline Vertex45CompactT(const Vertex45CompactT& vertex) : pt(vertex.pt), count(vertex.count) {} + inline Vertex45CompactT& operator=(const Vertex45CompactT& vertex){ + pt = vertex.pt; count = vertex.count; return *this; } + inline bool operator==(const Vertex45CompactT& vertex) const { + return pt == vertex.pt && count == vertex.count; } + inline bool operator!=(const Vertex45CompactT& vertex) const { return !((*this) == vertex); } + inline bool operator==(const std::pair<Point, Point>& vertex) const { return false; } + inline bool operator!=(const std::pair<Point, Point>& vertex) const { return !((*this) == vertex); } + inline bool operator<(const Vertex45CompactT& vertex) const { + if(pt.x() < vertex.pt.x()) return true; + if(pt.x() == vertex.pt.x()) { + return pt.y() < vertex.pt.y(); + } + return false; + } + inline bool operator>(const Vertex45CompactT& vertex) const { return vertex < (*this); } + inline bool operator<=(const Vertex45CompactT& vertex) const { return !((*this) > vertex); } + inline bool operator>=(const Vertex45CompactT& vertex) const { return !((*this) < vertex); } + inline bool haveVertex45(int index) const { return count[index]; } + inline Vertex45T operator[](int index) const { + return Vertex45T(pt, index-1, count[index]); } + }; + + typedef Vertex45CompactT<Vertex45Count> Vertex45Compact; + +// inline std::ostream& operator<< (std::ostream& o, const Vertex45Compact& c) { +// o << c.pt << ", " << c.count; +// return o; +// } + + class Polygon45Formation { + private: + //definitions + typedef std::map<Vertex45, ActiveTail45*, lessVertex45> Polygon45FormationData; + typedef typename Polygon45FormationData::iterator iterator; + typedef typename Polygon45FormationData::const_iterator const_iterator; + + //data + Polygon45FormationData scanData_; + Unit x_; + int justBefore_; + int fractureHoles_; + public: + inline Polygon45Formation() : scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false), fractureHoles_(0) { + lessVertex45 lessElm(&x_, &justBefore_); + scanData_ = Polygon45FormationData(lessElm); + } + inline Polygon45Formation(bool fractureHoles) : scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false), fractureHoles_(fractureHoles) { + lessVertex45 lessElm(&x_, &justBefore_); + scanData_ = Polygon45FormationData(lessElm); + } + inline Polygon45Formation(const Polygon45Formation& that) : + scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false), fractureHoles_(0) { (*this) = that; } + inline Polygon45Formation& operator=(const Polygon45Formation& that) { + x_ = that.x_; + justBefore_ = that.justBefore_; + fractureHoles_ = that.fractureHoles_; + lessVertex45 lessElm(&x_, &justBefore_); + scanData_ = Polygon45FormationData(lessElm); + for(const_iterator itr = that.scanData_.begin(); itr != that.scanData_.end(); ++itr){ + scanData_.insert(scanData_.end(), *itr); + } + return *this; + } + + //cT is an output container of Polygon45 or Polygon45WithHoles + //iT is an iterator over Vertex45 elements + //inputBegin - inputEnd is a range of sorted iT that represents + //one or more scanline stops worth of data + template <class cT, class iT> + void scan(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "1\n"; + while(inputBegin != inputEnd) { + //std::cout << "2\n"; + x_ = (*inputBegin).pt.x(); + //std::cout << "SCAN FORMATION " << x_ << std::endl; + //std::cout << "x_ = " << x_ << std::endl; + //std::cout << "scan line size: " << scanData_.size() << std::endl; + inputBegin = processEvent_(output, inputBegin, inputEnd); + } + } + + private: + //functions + template <class cT, class cT2> + inline std::pair<int, ActiveTail45*> processPoint_(cT& output, cT2& elements, Point point, + Vertex45Count& counts, ActiveTail45** tails, Vertex45Count& incoming) { + //std::cout << point << std::endl; + //std::cout << counts[0] << " "; + //std::cout << counts[1] << " "; + //std::cout << counts[2] << " "; + //std::cout << counts[3] << "\n"; + //std::cout << incoming[0] << " "; + //std::cout << incoming[1] << " "; + //std::cout << incoming[2] << " "; + //std::cout << incoming[3] << "\n"; + //join any closing solid corners + ActiveTail45* returnValue = 0; + int returnCount = 0; + for(int i = 0; i < 3; ++i) { + //std::cout << i << std::endl; + if(counts[i] == -1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < 4; ++j) { + //std::cout << j << std::endl; + if(counts[j]) { + if(counts[j] == 1) { + //std::cout << "case1: " << i << " " << j << std::endl; + //if a figure is closed it will be written out by this function to output + ActiveTail45::joinChains(point, tails[i], tails[j], true, output); + counts[i] = 0; + counts[j] = 0; + tails[i] = 0; + tails[j] = 0; + } + break; + } + } + } + } + //find any pairs of incoming edges that need to create pair for leading solid + //std::cout << "checking case2\n"; + for(int i = 0; i < 3; ++i) { + //std::cout << i << std::endl; + if(incoming[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < 4; ++j) { + //std::cout << j << std::endl; + if(incoming[j]) { + if(incoming[j] == -1) { + //std::cout << "case2: " << i << " " << j << std::endl; + //std::cout << "creating active tail pair\n"; + std::pair<ActiveTail45*, ActiveTail45*> tailPair = + ActiveTail45::createActiveTail45sAsPair(point, true, 0, fractureHoles_ != 0); + //tailPair.first->print(); + //tailPair.second->print(); + if(j == 3) { + //vertical active tail becomes return value + returnValue = tailPair.first; + returnCount = 1; + } else { + Vertex45 vertex(point, i -1, incoming[i]); + //std::cout << "new element " << j-1 << " " << -1 << std::endl; + elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, -1), tailPair.first)); + } + //std::cout << "new element " << i-1 << " " << 1 << std::endl; + elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, i -1, 1), tailPair.second)); + incoming[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + } + + //find any active tail that needs to pass through to an incoming edge + //we expect to find no more than two pass through + + //find pass through with solid on top + //std::cout << "checking case 3\n"; + for(int i = 0; i < 4; ++i) { + //std::cout << i << std::endl; + if(counts[i] != 0) { + if(counts[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = 3; j >= 0; --j) { + if(incoming[j] != 0) { + if(incoming[j] == 1) { + //std::cout << "case3: " << i << " " << j << std::endl; + //tails[i]->print(); + //pass through solid on top + tails[i]->pushPoint(point); + //std::cout << "after push\n"; + if(j == 3) { + returnValue = tails[i]; + returnCount = -1; + } else { + elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, incoming[j]), tails[i])); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + //std::cout << "checking case 4\n"; + //find pass through with solid on bottom + for(int i = 3; i >= 0; --i) { + if(counts[i] != 0) { + if(counts[i] == -1) { + for(int j = 0; j < 4; ++j) { + if(incoming[j] != 0) { + if(incoming[j] == -1) { + //std::cout << "case4: " << i << " " << j << std::endl; + //pass through solid on bottom + tails[i]->pushPoint(point); + if(j == 3) { + returnValue = tails[i]; + returnCount = 1; + } else { + //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, incoming[j]), tails[i])); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + + //find the end of a hole or the beginning of a hole + + //find end of a hole + for(int i = 0; i < 3; ++i) { + if(counts[i] != 0) { + for(int j = i+1; j < 4; ++j) { + if(counts[j] != 0) { + //std::cout << "case5: " << i << " " << j << std::endl; + //we are ending a hole and may potentially close a figure and have to handle the hole + returnValue = ActiveTail45::joinChains(point, tails[i], tails[j], false, output); + tails[i] = 0; + tails[j] = 0; + counts[i] = 0; + counts[j] = 0; + break; + } + } + break; + } + } + //find beginning of a hole + for(int i = 0; i < 3; ++i) { + if(incoming[i] != 0) { + for(int j = i+1; j < 4; ++j) { + if(incoming[j] != 0) { + //std::cout << "case6: " << i << " " << j << std::endl; + //we are beginning a empty space + ActiveTail45* holep = 0; + if(counts[3] == 0) holep = tails[3]; + std::pair<ActiveTail45*, ActiveTail45*> tailPair = + ActiveTail45::createActiveTail45sAsPair(point, false, holep, fractureHoles_ != 0); + if(j == 3) { + returnValue = tailPair.first; + returnCount = -1; + } else { + //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, incoming[j]), tailPair.first)); + } + //std::cout << "new element " << i-1 << " " << incoming[i] << std::endl; + elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, i -1, incoming[i]), tailPair.second)); + incoming[i] = 0; + incoming[j] = 0; + break; + } + } + break; + } + } + //assert that tails, counts and incoming are all null + return std::pair<int, ActiveTail45*>(returnCount, returnValue); + } + + template <class cT, class iT> + inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "processEvent_\n"; + justBefore_ = true; + //collect up all elements from the tree that are at the y + //values of events in the input queue + //create vector of new elements to add into tree + ActiveTail45* verticalTail = 0; + int verticalCount = 0; + iT currentIter = inputBegin; + std::vector<iterator> elementIters; + std::vector<std::pair<Vertex45, ActiveTail45*> > elements; + while(currentIter != inputEnd && currentIter->pt.x() == x_) { + //std::cout << "loop\n"; + Unit currentY = (*currentIter).pt.y(); + iterator iter = lookUp_(currentY); + //int counts[4] = {0, 0, 0, 0}; + Vertex45Count counts; + ActiveTail45* tails[4] = {0, 0, 0, verticalTail}; + //std::cout << "finding elements in tree\n"; + while(iter != scanData_.end() && + iter->first.evalAtX(x_) == currentY) { + //std::cout << "loop2\n"; + elementIters.push_back(iter); + int index = iter->first.rise + 1; + //std::cout << index << " " << iter->first.count << std::endl; + counts[index] = iter->first.count; + tails[index] = iter->second; + ++iter; + } + //int incoming[4] = {0, 0, 0, 0}; + Vertex45Count incoming; + //std::cout << "aggregating\n"; + do { + //std::cout << "loop3\n"; + Vertex45Compact currentVertex(*currentIter); + incoming += currentVertex.count; + ++currentIter; + } while(currentIter != inputEnd && currentIter->pt.y() == currentY && + currentIter->pt.x() == x_); + //now counts and tails have the data from the left and + //incoming has the data from the right at this point + //cancel out any end points + //std::cout << counts[0] << " "; + //std::cout << counts[1] << " "; + //std::cout << counts[2] << " "; + //std::cout << counts[3] << "\n"; + //std::cout << incoming[0] << " "; + //std::cout << incoming[1] << " "; + //std::cout << incoming[2] << " "; + //std::cout << incoming[3] << "\n"; + if(verticalTail) { + counts[3] = -verticalCount; + } + incoming[3] *= -1; + for(unsigned int i = 0; i < 4; ++i) incoming[i] += counts[i]; + //std::cout << "calling processPoint_\n"; + std::pair<int, ActiveTail45*> result = processPoint_(output, elements, Point(x_, currentY), counts, tails, incoming); + verticalCount = result.first; + verticalTail = result.second; + //if(verticalTail) std::cout << "have vertical tail\n"; + //std::cout << "verticalCount: " << verticalCount << std::endl; + if(verticalTail && !verticalCount) { + //we got a hole out of the point we just processed + //iter is still at the next y element above the current y value in the tree + //std::cout << "checking whether ot handle hole\n"; + if(currentIter == inputEnd || + currentIter->pt.x() != x_ || + currentIter->pt.y() >= iter->first.evalAtX(x_)) { + //std::cout << "handle hole here\n"; + if(fractureHoles_) { + //std::cout << "fracture hole here\n"; + //we need to handle the hole now and not at the next input vertex + ActiveTail45* at = iter->second; + Point point(x_, iter->first.evalAtX(x_)); + verticalTail->getOtherActiveTail()->pushPoint(point); + iter->second = verticalTail->getOtherActiveTail(); + at->pushPoint(point); + verticalTail->join(at); + delete at; + delete verticalTail; + verticalTail = 0; + } else { + //std::cout << "push hole onto list\n"; + iter->second->addHole(verticalTail); + verticalTail = 0; + } + } + } + } + //std::cout << "erasing\n"; + //erase all elements from the tree + for(typename std::vector<iterator>::iterator iter = elementIters.begin(); + iter != elementIters.end(); ++iter) { + //std::cout << "erasing loop\n"; + scanData_.erase(*iter); + } + //switch comparison tie breaking policy + justBefore_ = false; + //add new elements into tree + //std::cout << "inserting\n"; + for(typename std::vector<std::pair<Vertex45, ActiveTail45*> >::iterator iter = elements.begin(); + iter != elements.end(); ++iter) { + //std::cout << "inserting loop\n"; + scanData_.insert(scanData_.end(), *iter); + } + //std::cout << "end processEvent\n"; + return currentIter; + } + + inline iterator lookUp_(Unit y){ + //if just before then we need to look from 1 not -1 + return scanData_.lower_bound(Vertex45(Point(x_, y), -1+2*justBefore_, 0)); + } + + }; + + template <typename stream_type> + static inline bool testPolygon45FormationRect(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(true); + std::vector<Polygon45> polys; + std::vector<Vertex45> data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 2, -1)); + data.push_back(Vertex45(Point(10, 10), 2, 1)); + data.push_back(Vertex45(Point(10, 10), 0, 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45FormationP1(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(true); + std::vector<Polygon45> polys; + std::vector<Vertex45> data; + data.push_back(Vertex45(Point(0, 0), 1, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 1, -1)); + data.push_back(Vertex45(Point(10, 10), 1, -1)); + data.push_back(Vertex45(Point(10, 10), 2, -1)); + data.push_back(Vertex45(Point(10, 20), 2, 1)); + data.push_back(Vertex45(Point(10, 20), 1, 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + //polygon45set class + + template <typename stream_type> + static inline bool testPolygon45FormationP2(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(true); + std::vector<Polygon45> polys; + std::vector<Vertex45> data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 1, -1)); + data.push_back(Vertex45(Point(10, 0), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 1, 1)); + data.push_back(Vertex45(Point(10, 10), 1, 1)); + data.push_back(Vertex45(Point(10, 10), 0, -1)); + data.push_back(Vertex45(Point(20, 10), 1, -1)); + data.push_back(Vertex45(Point(20, 10), 0, 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + //polygon45set class + + template <typename stream_type> + static inline bool testPolygon45FormationStar1(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(true); + std::vector<Polygon45> polys; + std::vector<Vertex45> data; + // result == 0 8 -1 1 + data.push_back(Vertex45(Point(0, 8), -1, 1)); + // result == 0 8 1 -1 + data.push_back(Vertex45(Point(0, 8), 1, -1)); + // result == 4 0 1 1 + data.push_back(Vertex45(Point(4, 0), 1, 1)); + // result == 4 0 2 1 + data.push_back(Vertex45(Point(4, 0), 2, 1)); + // result == 4 4 2 -1 + data.push_back(Vertex45(Point(4, 4), 2, -1)); + // result == 4 4 -1 -1 + data.push_back(Vertex45(Point(4, 4), -1, -1)); + // result == 4 12 1 1 + data.push_back(Vertex45(Point(4, 12), 1, 1)); + // result == 4 12 2 1 + data.push_back(Vertex45(Point(4, 12), 2, 1)); + // result == 4 16 2 -1 + data.push_back(Vertex45(Point(4, 16), 2, 1)); + // result == 4 16 -1 -1 + data.push_back(Vertex45(Point(4, 16), -1, -1)); + // result == 6 2 1 -1 + data.push_back(Vertex45(Point(6, 2), 1, -1)); + // result == 6 14 -1 1 + data.push_back(Vertex45(Point(6, 14), -1, 1)); + // result == 6 2 -1 1 + data.push_back(Vertex45(Point(6, 2), -1, 1)); + // result == 6 14 1 -1 + data.push_back(Vertex45(Point(6, 14), 1, -1)); + // result == 8 0 -1 -1 + data.push_back(Vertex45(Point(8, 0), -1, -1)); + // result == 8 0 2 -1 + data.push_back(Vertex45(Point(8, 0), 2, -1)); + // result == 8 4 2 1 + data.push_back(Vertex45(Point(8, 4), 2, 1)); + // result == 8 4 1 1 + data.push_back(Vertex45(Point(8, 4), 1, 1)); + // result == 8 12 -1 -1 + data.push_back(Vertex45(Point(8, 12), -1, -1)); + // result == 8 12 2 -1 + data.push_back(Vertex45(Point(8, 12), 2, -1)); + // result == 8 16 2 1 + data.push_back(Vertex45(Point(8, 16), 2, 1)); + // result == 8 16 1 1 + data.push_back(Vertex45(Point(8, 16), 1, 1)); + // result == 12 8 1 -1 + data.push_back(Vertex45(Point(12, 8), 1, -1)); + // result == 12 8 -1 1 + data.push_back(Vertex45(Point(12, 8), -1, 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45FormationStar2(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(true); + std::vector<Polygon45> polys; + Scan45 scan45; + std::vector<Vertex45 > result; + std::vector<Scan45Vertex> vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,4), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,4), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,12), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + count = Count2(0, 1); + ncount = count.invert(); + vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,8), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + sortScan45Vector(vertices); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + + gtlsort(result.begin(), result.end()); + pf.scan(polys, result.begin(), result.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45FormationStarHole1(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(true); + std::vector<Polygon45> polys; + std::vector<Vertex45> data; + // result == 0 8 -1 1 + data.push_back(Vertex45(Point(0, 8), -1, 1)); + // result == 0 8 1 -1 + data.push_back(Vertex45(Point(0, 8), 1, -1)); + // result == 4 0 1 1 + data.push_back(Vertex45(Point(4, 0), 1, 1)); + // result == 4 0 2 1 + data.push_back(Vertex45(Point(4, 0), 2, 1)); + // result == 4 4 2 -1 + data.push_back(Vertex45(Point(4, 4), 2, -1)); + // result == 4 4 -1 -1 + data.push_back(Vertex45(Point(4, 4), -1, -1)); + // result == 4 12 1 1 + data.push_back(Vertex45(Point(4, 12), 1, 1)); + // result == 4 12 2 1 + data.push_back(Vertex45(Point(4, 12), 2, 1)); + // result == 4 16 2 -1 + data.push_back(Vertex45(Point(4, 16), 2, 1)); + // result == 4 16 -1 -1 + data.push_back(Vertex45(Point(4, 16), -1, -1)); + // result == 6 2 1 -1 + data.push_back(Vertex45(Point(6, 2), 1, -1)); + // result == 6 14 -1 1 + data.push_back(Vertex45(Point(6, 14), -1, 1)); + // result == 6 2 -1 1 + data.push_back(Vertex45(Point(6, 2), -1, 1)); + // result == 6 14 1 -1 + data.push_back(Vertex45(Point(6, 14), 1, -1)); + // result == 8 0 -1 -1 + data.push_back(Vertex45(Point(8, 0), -1, -1)); + // result == 8 0 2 -1 + data.push_back(Vertex45(Point(8, 0), 2, -1)); + // result == 8 4 2 1 + data.push_back(Vertex45(Point(8, 4), 2, 1)); + // result == 8 4 1 1 + data.push_back(Vertex45(Point(8, 4), 1, 1)); + // result == 8 12 -1 -1 + data.push_back(Vertex45(Point(8, 12), -1, -1)); + // result == 8 12 2 -1 + data.push_back(Vertex45(Point(8, 12), 2, -1)); + // result == 8 16 2 1 + data.push_back(Vertex45(Point(8, 16), 2, 1)); + // result == 8 16 1 1 + data.push_back(Vertex45(Point(8, 16), 1, 1)); + // result == 12 8 1 -1 + data.push_back(Vertex45(Point(12, 8), 1, -1)); + // result == 12 8 -1 1 + data.push_back(Vertex45(Point(12, 8), -1, 1)); + + data.push_back(Vertex45(Point(6, 4), 1, -1)); + data.push_back(Vertex45(Point(6, 4), 2, -1)); + data.push_back(Vertex45(Point(6, 8), -1, 1)); + data.push_back(Vertex45(Point(6, 8), 2, 1)); + data.push_back(Vertex45(Point(8, 6), -1, -1)); + data.push_back(Vertex45(Point(8, 6), 1, 1)); + + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45FormationStarHole2(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(false); + std::vector<Polygon45WithHoles> polys; + std::vector<Vertex45> data; + // result == 0 8 -1 1 + data.push_back(Vertex45(Point(0, 8), -1, 1)); + // result == 0 8 1 -1 + data.push_back(Vertex45(Point(0, 8), 1, -1)); + // result == 4 0 1 1 + data.push_back(Vertex45(Point(4, 0), 1, 1)); + // result == 4 0 2 1 + data.push_back(Vertex45(Point(4, 0), 2, 1)); + // result == 4 4 2 -1 + data.push_back(Vertex45(Point(4, 4), 2, -1)); + // result == 4 4 -1 -1 + data.push_back(Vertex45(Point(4, 4), -1, -1)); + // result == 4 12 1 1 + data.push_back(Vertex45(Point(4, 12), 1, 1)); + // result == 4 12 2 1 + data.push_back(Vertex45(Point(4, 12), 2, 1)); + // result == 4 16 2 -1 + data.push_back(Vertex45(Point(4, 16), 2, 1)); + // result == 4 16 -1 -1 + data.push_back(Vertex45(Point(4, 16), -1, -1)); + // result == 6 2 1 -1 + data.push_back(Vertex45(Point(6, 2), 1, -1)); + // result == 6 14 -1 1 + data.push_back(Vertex45(Point(6, 14), -1, 1)); + // result == 6 2 -1 1 + data.push_back(Vertex45(Point(6, 2), -1, 1)); + // result == 6 14 1 -1 + data.push_back(Vertex45(Point(6, 14), 1, -1)); + // result == 8 0 -1 -1 + data.push_back(Vertex45(Point(8, 0), -1, -1)); + // result == 8 0 2 -1 + data.push_back(Vertex45(Point(8, 0), 2, -1)); + // result == 8 4 2 1 + data.push_back(Vertex45(Point(8, 4), 2, 1)); + // result == 8 4 1 1 + data.push_back(Vertex45(Point(8, 4), 1, 1)); + // result == 8 12 -1 -1 + data.push_back(Vertex45(Point(8, 12), -1, -1)); + // result == 8 12 2 -1 + data.push_back(Vertex45(Point(8, 12), 2, -1)); + // result == 8 16 2 1 + data.push_back(Vertex45(Point(8, 16), 2, 1)); + // result == 8 16 1 1 + data.push_back(Vertex45(Point(8, 16), 1, 1)); + // result == 12 8 1 -1 + data.push_back(Vertex45(Point(12, 8), 1, -1)); + // result == 12 8 -1 1 + data.push_back(Vertex45(Point(12, 8), -1, 1)); + + data.push_back(Vertex45(Point(6, 4), 1, -1)); + data.push_back(Vertex45(Point(6, 4), 2, -1)); + data.push_back(Vertex45(Point(6, 12), -1, 1)); + data.push_back(Vertex45(Point(6, 12), 2, 1)); + data.push_back(Vertex45(Point(10, 8), -1, -1)); + data.push_back(Vertex45(Point(10, 8), 1, 1)); + + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45Formation(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(false); + std::vector<Polygon45WithHoles> polys; + std::vector<Vertex45> data; + + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 100), 2, -1)); + data.push_back(Vertex45(Point(0, 100), 0, -1)); + data.push_back(Vertex45(Point(100, 0), 0, -1)); + data.push_back(Vertex45(Point(100, 0), 2, -1)); + data.push_back(Vertex45(Point(100, 100), 2, 1)); + data.push_back(Vertex45(Point(100, 100), 0, 1)); + + data.push_back(Vertex45(Point(2, 2), 0, -1)); + data.push_back(Vertex45(Point(2, 2), 2, -1)); + data.push_back(Vertex45(Point(2, 10), 2, 1)); + data.push_back(Vertex45(Point(2, 10), 0, 1)); + data.push_back(Vertex45(Point(10, 2), 0, 1)); + data.push_back(Vertex45(Point(10, 2), 2, 1)); + data.push_back(Vertex45(Point(10, 10), 2, -1)); + data.push_back(Vertex45(Point(10, 10), 0, -1)); + + data.push_back(Vertex45(Point(2, 12), 0, -1)); + data.push_back(Vertex45(Point(2, 12), 2, -1)); + data.push_back(Vertex45(Point(2, 22), 2, 1)); + data.push_back(Vertex45(Point(2, 22), 0, 1)); + data.push_back(Vertex45(Point(10, 12), 0, 1)); + data.push_back(Vertex45(Point(10, 12), 2, 1)); + data.push_back(Vertex45(Point(10, 22), 2, -1)); + data.push_back(Vertex45(Point(10, 22), 0, -1)); + + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + + class Polygon45Tiling { + private: + //definitions + typedef std::map<Vertex45, ActiveTail45*, lessVertex45> Polygon45FormationData; + typedef typename Polygon45FormationData::iterator iterator; + typedef typename Polygon45FormationData::const_iterator const_iterator; + + //data + Polygon45FormationData scanData_; + Unit x_; + int justBefore_; + public: + inline Polygon45Tiling() : scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false) { + lessVertex45 lessElm(&x_, &justBefore_); + scanData_ = Polygon45FormationData(lessElm); + } + inline Polygon45Tiling(const Polygon45Tiling& that) : + scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false) { (*this) = that; } + inline Polygon45Tiling& operator=(const Polygon45Tiling& that) { + x_ = that.x_; + justBefore_ = that.justBefore_; + lessVertex45 lessElm(&x_, &justBefore_); + scanData_ = Polygon45FormationData(lessElm); + for(const_iterator itr = that.scanData_.begin(); itr != that.scanData_.end(); ++itr){ + scanData_.insert(scanData_.end(), *itr); + } + return *this; + } + + //cT is an output container of Polygon45 or Polygon45WithHoles + //iT is an iterator over Vertex45 elements + //inputBegin - inputEnd is a range of sorted iT that represents + //one or more scanline stops worth of data + template <class cT, class iT> + void scan(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "1\n"; + while(inputBegin != inputEnd) { + //std::cout << "2\n"; + x_ = (*inputBegin).pt.x(); + //std::cout << "SCAN FORMATION " << x_ << std::endl; + //std::cout << "x_ = " << x_ << std::endl; + //std::cout << "scan line size: " << scanData_.size() << std::endl; + inputBegin = processEvent_(output, inputBegin, inputEnd); + } + } + + private: + //functions + + inline void getVerticalPair_(std::pair<ActiveTail45*, ActiveTail45*>& verticalPair, + iterator previter) { + ActiveTail45* iterTail = (*previter).second; + Point prevPoint(x_, previter->first.evalAtX(x_)); + iterTail->pushPoint(prevPoint); + std::pair<ActiveTail45*, ActiveTail45*> tailPair = + ActiveTail45::createActiveTail45sAsPair(prevPoint, true, 0, false); + verticalPair.first = iterTail; + verticalPair.second = tailPair.first; + (*previter).second = tailPair.second; + } + + template <class cT, class cT2> + inline std::pair<int, ActiveTail45*> processPoint_(cT& output, cT2& elements, + std::pair<ActiveTail45*, ActiveTail45*>& verticalPair, + iterator previter, Point point, + Vertex45Count& counts, ActiveTail45** tails, Vertex45Count& incoming) { + //std::cout << point << std::endl; + //std::cout << counts[0] << " "; + //std::cout << counts[1] << " "; + //std::cout << counts[2] << " "; + //std::cout << counts[3] << "\n"; + //std::cout << incoming[0] << " "; + //std::cout << incoming[1] << " "; + //std::cout << incoming[2] << " "; + //std::cout << incoming[3] << "\n"; + //join any closing solid corners + ActiveTail45* returnValue = 0; + std::pair<ActiveTail45*, ActiveTail45*> verticalPairOut; + verticalPairOut.first = 0; + verticalPairOut.second = 0; + int returnCount = 0; + for(int i = 0; i < 3; ++i) { + //std::cout << i << std::endl; + if(counts[i] == -1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < 4; ++j) { + //std::cout << j << std::endl; + if(counts[j]) { + if(counts[j] == 1) { + //std::cout << "case1: " << i << " " << j << std::endl; + //if a figure is closed it will be written out by this function to output + ActiveTail45::joinChains(point, tails[i], tails[j], true, output); + counts[i] = 0; + counts[j] = 0; + tails[i] = 0; + tails[j] = 0; + } + break; + } + } + } + } + //find any pairs of incoming edges that need to create pair for leading solid + //std::cout << "checking case2\n"; + for(int i = 0; i < 3; ++i) { + //std::cout << i << std::endl; + if(incoming[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < 4; ++j) { + //std::cout << j << std::endl; + if(incoming[j]) { + if(incoming[j] == -1) { + //std::cout << "case2: " << i << " " << j << std::endl; + //std::cout << "creating active tail pair\n"; + std::pair<ActiveTail45*, ActiveTail45*> tailPair = + ActiveTail45::createActiveTail45sAsPair(point, true, 0, false); + //tailPair.first->print(); + //tailPair.second->print(); + if(j == 3) { + //vertical active tail becomes return value + returnValue = tailPair.first; + returnCount = 1; + } else { + Vertex45 vertex(point, i -1, incoming[i]); + //std::cout << "new element " << j-1 << " " << -1 << std::endl; + elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, -1), tailPair.first)); + } + //std::cout << "new element " << i-1 << " " << 1 << std::endl; + elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, i -1, 1), tailPair.second)); + incoming[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + } + + //find any active tail that needs to pass through to an incoming edge + //we expect to find no more than two pass through + + //find pass through with solid on top + //std::cout << "checking case 3\n"; + for(int i = 0; i < 4; ++i) { + //std::cout << i << std::endl; + if(counts[i] != 0) { + if(counts[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = 3; j >= 0; --j) { + if(incoming[j] != 0) { + if(incoming[j] == 1) { + //std::cout << "case3: " << i << " " << j << std::endl; + //tails[i]->print(); + //pass through solid on top + if(i != 3) + tails[i]->pushPoint(point); + //std::cout << "after push\n"; + if(j == 3) { + returnValue = tails[i]; + returnCount = -1; + } else { + verticalPairOut.first = tails[i]; + std::pair<ActiveTail45*, ActiveTail45*> tailPair = + ActiveTail45::createActiveTail45sAsPair(point, true, 0, false); + verticalPairOut.second = tailPair.first; + elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, incoming[j]), + tailPair.second)); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + //std::cout << "checking case 4\n"; + //find pass through with solid on bottom + for(int i = 3; i >= 0; --i) { + if(counts[i] != 0) { + if(counts[i] == -1) { + for(int j = 0; j < 4; ++j) { + if(incoming[j] != 0) { + if(incoming[j] == -1) { + //std::cout << "case4: " << i << " " << j << std::endl; + //pass through solid on bottom + if(i == 3) { + //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + if(j == 3) { + returnValue = tails[i]; + returnCount = 1; + } else { + tails[i]->pushPoint(point); + elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, incoming[j]), tails[i])); + } + } else if(j == 3) { + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + ActiveTail45::joinChains(point, tails[i], verticalPair.first, true, output); + returnValue = verticalPair.second; + returnCount = 1; + } else { + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + ActiveTail45::joinChains(point, tails[i], verticalPair.first, true, output); + verticalPair.second->pushPoint(point); + elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, incoming[j]), + verticalPair.second)); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + + //find the end of a hole or the beginning of a hole + + //find end of a hole + for(int i = 0; i < 3; ++i) { + if(counts[i] != 0) { + for(int j = i+1; j < 4; ++j) { + if(counts[j] != 0) { + //std::cout << "case5: " << i << " " << j << std::endl; + //we are ending a hole and may potentially close a figure and have to handle the hole + tails[i]->pushPoint(point); + verticalPairOut.first = tails[i]; + if(j == 3) { + verticalPairOut.second = tails[j]; + } else { + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + ActiveTail45::joinChains(point, tails[j], verticalPair.first, true, output); + verticalPairOut.second = verticalPair.second; + } + tails[i] = 0; + tails[j] = 0; + counts[i] = 0; + counts[j] = 0; + break; + } + } + break; + } + } + //find beginning of a hole + for(int i = 0; i < 3; ++i) { + if(incoming[i] != 0) { + for(int j = i+1; j < 4; ++j) { + if(incoming[j] != 0) { + //std::cout << "case6: " << i << " " << j << std::endl; + //we are beginning a empty space + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + verticalPair.second->pushPoint(point); + if(j == 3) { + returnValue = verticalPair.first; + returnCount = -1; + } else { + std::pair<ActiveTail45*, ActiveTail45*> tailPair = + ActiveTail45::createActiveTail45sAsPair(point, true, 0, false); + //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, j -1, incoming[j]), tailPair.second)); + verticalPairOut.second = tailPair.first; + verticalPairOut.first = verticalPair.first; + } + //std::cout << "new element " << i-1 << " " << incoming[i] << std::endl; + elements.push_back(std::pair<Vertex45, ActiveTail45*>(Vertex45(point, i -1, incoming[i]), verticalPair.second)); + incoming[i] = 0; + incoming[j] = 0; + break; + } + } + break; + } + } + verticalPair = verticalPairOut; + //assert that verticalPair is either both null, or neither null + //assert that returnValue is null if verticalPair is not null + //assert that tails, counts and incoming are all null + return std::pair<int, ActiveTail45*>(returnCount, returnValue); + } + + template <class cT, class iT> + inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "processEvent_\n"; + justBefore_ = true; + //collect up all elements from the tree that are at the y + //values of events in the input queue + //create vector of new elements to add into tree + ActiveTail45* verticalTail = 0; + std::pair<ActiveTail45*, ActiveTail45*> verticalPair; + verticalPair.first = 0; + verticalPair.second = 0; + int verticalCount = 0; + iT currentIter = inputBegin; + std::vector<iterator> elementIters; + std::vector<std::pair<Vertex45, ActiveTail45*> > elements; + while(currentIter != inputEnd && currentIter->pt.x() == x_) { + //std::cout << "loop\n"; + Unit currentY = (*currentIter).pt.y(); + iterator iter = lookUp_(currentY); + //int counts[4] = {0, 0, 0, 0}; + Vertex45Count counts; + ActiveTail45* tails[4] = {0, 0, 0, verticalTail}; + //std::cout << "finding elements in tree\n"; + iterator previter = iter; + if(previter != scanData_.end() && + previter->first.evalAtX(x_) >= currentY && + previter != scanData_.begin()) + --previter; + while(iter != scanData_.end() && + iter->first.evalAtX(x_) == currentY) { + //std::cout << "loop2\n"; + elementIters.push_back(iter); + int index = iter->first.rise + 1; + //std::cout << index << " " << iter->first.count << std::endl; + counts[index] = iter->first.count; + tails[index] = iter->second; + ++iter; + } + //int incoming[4] = {0, 0, 0, 0}; + Vertex45Count incoming; + //std::cout << "aggregating\n"; + do { + //std::cout << "loop3\n"; + Vertex45Compact currentVertex(*currentIter); + incoming += currentVertex.count; + ++currentIter; + } while(currentIter != inputEnd && currentIter->pt.y() == currentY && + currentIter->pt.x() == x_); + //now counts and tails have the data from the left and + //incoming has the data from the right at this point + //cancel out any end points + //std::cout << counts[0] << " "; + //std::cout << counts[1] << " "; + //std::cout << counts[2] << " "; + //std::cout << counts[3] << "\n"; + //std::cout << incoming[0] << " "; + //std::cout << incoming[1] << " "; + //std::cout << incoming[2] << " "; + //std::cout << incoming[3] << "\n"; + if(verticalTail) { + counts[3] = -verticalCount; + } + incoming[3] *= -1; + for(unsigned int i = 0; i < 4; ++i) incoming[i] += counts[i]; + //std::cout << "calling processPoint_\n"; + std::pair<int, ActiveTail45*> result = processPoint_(output, elements, verticalPair, previter, + Point(x_, currentY), counts, tails, incoming); + verticalCount = result.first; + verticalTail = result.second; + if(verticalPair.first != 0 && iter != scanData_.end() && + (currentIter == inputEnd || currentIter->pt.x() != x_ || + currentIter->pt.y() > (*iter).first.evalAtX(x_))) { + //splice vertical pair into edge above + ActiveTail45* tailabove = (*iter).second; + Point point(x_, (*iter).first.evalAtX(x_)); + verticalPair.second->pushPoint(point); + ActiveTail45::joinChains(point, tailabove, verticalPair.first, true, output); + (*iter).second = verticalPair.second; + verticalPair.first = 0; + verticalPair.second = 0; + } + } + //std::cout << "erasing\n"; + //erase all elements from the tree + for(typename std::vector<iterator>::iterator iter = elementIters.begin(); + iter != elementIters.end(); ++iter) { + //std::cout << "erasing loop\n"; + scanData_.erase(*iter); + } + //switch comparison tie breaking policy + justBefore_ = false; + //add new elements into tree + //std::cout << "inserting\n"; + for(typename std::vector<std::pair<Vertex45, ActiveTail45*> >::iterator iter = elements.begin(); + iter != elements.end(); ++iter) { + //std::cout << "inserting loop\n"; + scanData_.insert(scanData_.end(), *iter); + } + //std::cout << "end processEvent\n"; + return currentIter; + } + + inline iterator lookUp_(Unit y){ + //if just before then we need to look from 1 not -1 + return scanData_.lower_bound(Vertex45(Point(x_, y), -1+2*justBefore_, 0)); + } + + }; + + template <typename stream_type> + static inline bool testPolygon45TilingRect(stream_type& stdcout) { + stdcout << "testing polygon tiling\n"; + Polygon45Tiling pf; + std::vector<Polygon45> polys; + std::vector<Vertex45> data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 2, -1)); + data.push_back(Vertex45(Point(10, 10), 2, 1)); + data.push_back(Vertex45(Point(10, 10), 0, 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45TilingP1(stream_type& stdcout) { + stdcout << "testing polygon tiling\n"; + Polygon45Tiling pf; + std::vector<Polygon45> polys; + std::vector<Vertex45> data; + data.push_back(Vertex45(Point(0, 0), 1, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 1, -1)); + data.push_back(Vertex45(Point(10, 10), 1, -1)); + data.push_back(Vertex45(Point(10, 10), 2, -1)); + data.push_back(Vertex45(Point(10, 20), 2, 1)); + data.push_back(Vertex45(Point(10, 20), 1, 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45TilingP2(stream_type& stdcout) { + stdcout << "testing polygon tiling\n"; + Polygon45Tiling pf; + std::vector<Polygon45> polys; + std::vector<Vertex45> data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 1, -1)); + data.push_back(Vertex45(Point(10, 0), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 1, 1)); + data.push_back(Vertex45(Point(10, 10), 1, 1)); + data.push_back(Vertex45(Point(10, 10), 0, -1)); + data.push_back(Vertex45(Point(20, 10), 1, -1)); + data.push_back(Vertex45(Point(20, 10), 0, 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45TilingP3(stream_type& stdcout) { + stdcout << "testing polygon tiling\n"; + Polygon45Tiling pf; + std::vector<Polygon45> polys; + std::vector<Vertex45> data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 0, -1)); + data.push_back(Vertex45(Point(20, 0), 0, -1)); + data.push_back(Vertex45(Point(20, 0), 2, -1)); + data.push_back(Vertex45(Point(10, 10), 1, -1)); + data.push_back(Vertex45(Point(10, 10), 0, 1)); + data.push_back(Vertex45(Point(20, 20), 1, 1)); + data.push_back(Vertex45(Point(20, 20), 2, 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45TilingP4(stream_type& stdcout) { + stdcout << "testing polygon tiling p4\n"; + Polygon45Tiling pf; + std::vector<Polygon45> polys; + std::vector<Vertex45> data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 0, -1)); + data.push_back(Vertex45(Point(10, 0), -1, 1)); + data.push_back(Vertex45(Point(10, 0), 0, -1)); + data.push_back(Vertex45(Point(20, 10), 2, 1)); + data.push_back(Vertex45(Point(20, 10), 0, 1)); + data.push_back(Vertex45(Point(20, -10), -1, -1)); + data.push_back(Vertex45(Point(20, -10), 2, -1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45TilingP5(stream_type& stdcout) { + stdcout << "testing polygon tiling P5\n"; + Polygon45Tiling pf; + std::vector<Polygon45> polys; + std::vector<Vertex45> data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 2, -1)); + data.push_back(Vertex45(Point(10, 10), 2, 1)); + data.push_back(Vertex45(Point(10, 10), 0, 1)); + + data.push_back(Vertex45(Point(1, 1), 0, -1)); + data.push_back(Vertex45(Point(1, 1), 1, 1)); + data.push_back(Vertex45(Point(2, 1), 0, 1)); + data.push_back(Vertex45(Point(2, 1), 1, -1)); + data.push_back(Vertex45(Point(2, 2), 1, -1)); + data.push_back(Vertex45(Point(2, 2), 0, 1)); + data.push_back(Vertex45(Point(3, 2), 1, 1)); + data.push_back(Vertex45(Point(3, 2), 0, -1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45TilingP6(stream_type& stdcout) { + stdcout << "testing polygon tiling P6\n"; + Polygon45Tiling pf; + std::vector<Polygon45> polys; + std::vector<Vertex45> data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 2, -1)); + data.push_back(Vertex45(Point(10, 10), 2, 1)); + data.push_back(Vertex45(Point(10, 10), 0, 1)); + + data.push_back(Vertex45(Point(1, 1), 0, -1)); + data.push_back(Vertex45(Point(1, 1), 2, -1)); + data.push_back(Vertex45(Point(1, 2), 2, 1)); + data.push_back(Vertex45(Point(1, 2), 0, 1)); + data.push_back(Vertex45(Point(2, 1), 0, 1)); + data.push_back(Vertex45(Point(2, 1), 2, 1)); + data.push_back(Vertex45(Point(2, 2), 2, -1)); + data.push_back(Vertex45(Point(2, 2), 0, -1)); + + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45TilingStar1(stream_type& stdcout) { + stdcout << "testing polygon tiling star1\n"; + Polygon45Tiling pf; + std::vector<Polygon45> polys; + std::vector<Vertex45> data; + // result == 0 8 -1 1 + data.push_back(Vertex45(Point(0, 8), -1, 1)); + // result == 0 8 1 -1 + data.push_back(Vertex45(Point(0, 8), 1, -1)); + // result == 4 0 1 1 + data.push_back(Vertex45(Point(4, 0), 1, 1)); + // result == 4 0 2 1 + data.push_back(Vertex45(Point(4, 0), 2, 1)); + // result == 4 4 2 -1 + data.push_back(Vertex45(Point(4, 4), 2, -1)); + // result == 4 4 -1 -1 + data.push_back(Vertex45(Point(4, 4), -1, -1)); + // result == 4 12 1 1 + data.push_back(Vertex45(Point(4, 12), 1, 1)); + // result == 4 12 2 1 + data.push_back(Vertex45(Point(4, 12), 2, 1)); + // result == 4 16 2 -1 + data.push_back(Vertex45(Point(4, 16), 2, 1)); + // result == 4 16 -1 -1 + data.push_back(Vertex45(Point(4, 16), -1, -1)); + // result == 6 2 1 -1 + data.push_back(Vertex45(Point(6, 2), 1, -1)); + // result == 6 14 -1 1 + data.push_back(Vertex45(Point(6, 14), -1, 1)); + // result == 6 2 -1 1 + data.push_back(Vertex45(Point(6, 2), -1, 1)); + // result == 6 14 1 -1 + data.push_back(Vertex45(Point(6, 14), 1, -1)); + // result == 8 0 -1 -1 + data.push_back(Vertex45(Point(8, 0), -1, -1)); + // result == 8 0 2 -1 + data.push_back(Vertex45(Point(8, 0), 2, -1)); + // result == 8 4 2 1 + data.push_back(Vertex45(Point(8, 4), 2, 1)); + // result == 8 4 1 1 + data.push_back(Vertex45(Point(8, 4), 1, 1)); + // result == 8 12 -1 -1 + data.push_back(Vertex45(Point(8, 12), -1, -1)); + // result == 8 12 2 -1 + data.push_back(Vertex45(Point(8, 12), 2, -1)); + // result == 8 16 2 1 + data.push_back(Vertex45(Point(8, 16), 2, 1)); + // result == 8 16 1 1 + data.push_back(Vertex45(Point(8, 16), 1, 1)); + // result == 12 8 1 -1 + data.push_back(Vertex45(Point(12, 8), 1, -1)); + // result == 12 8 -1 1 + data.push_back(Vertex45(Point(12, 8), -1, 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45TilingStar2(stream_type& stdcout) { + stdcout << "testing polygon tiling\n"; + Polygon45Tiling pf; + std::vector<Polygon45> polys; + + Scan45 scan45; + std::vector<Vertex45 > result; + std::vector<Scan45Vertex> vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,4), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,4), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,12), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + count = Count2(0, 1); + ncount = count.invert(); + vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,8), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + sortScan45Vector(vertices); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + + gtlsort(result.begin(), result.end()); + pf.scan(polys, result.begin(), result.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45TilingStarHole1(stream_type& stdcout) { + stdcout << "testing polygon tiling star hole 1\n"; + Polygon45Tiling pf; + std::vector<Polygon45> polys; + std::vector<Vertex45> data; + // result == 0 8 -1 1 + data.push_back(Vertex45(Point(0, 8), -1, 1)); + // result == 0 8 1 -1 + data.push_back(Vertex45(Point(0, 8), 1, -1)); + // result == 4 0 1 1 + data.push_back(Vertex45(Point(4, 0), 1, 1)); + // result == 4 0 2 1 + data.push_back(Vertex45(Point(4, 0), 2, 1)); + // result == 4 4 2 -1 + data.push_back(Vertex45(Point(4, 4), 2, -1)); + // result == 4 4 -1 -1 + data.push_back(Vertex45(Point(4, 4), -1, -1)); + // result == 4 12 1 1 + data.push_back(Vertex45(Point(4, 12), 1, 1)); + // result == 4 12 2 1 + data.push_back(Vertex45(Point(4, 12), 2, 1)); + // result == 4 16 2 -1 + data.push_back(Vertex45(Point(4, 16), 2, 1)); + // result == 4 16 -1 -1 + data.push_back(Vertex45(Point(4, 16), -1, -1)); + // result == 6 2 1 -1 + data.push_back(Vertex45(Point(6, 2), 1, -1)); + // result == 6 14 -1 1 + data.push_back(Vertex45(Point(6, 14), -1, 1)); + // result == 6 2 -1 1 + data.push_back(Vertex45(Point(6, 2), -1, 1)); + // result == 6 14 1 -1 + data.push_back(Vertex45(Point(6, 14), 1, -1)); + // result == 8 0 -1 -1 + data.push_back(Vertex45(Point(8, 0), -1, -1)); + // result == 8 0 2 -1 + data.push_back(Vertex45(Point(8, 0), 2, -1)); + // result == 8 4 2 1 + data.push_back(Vertex45(Point(8, 4), 2, 1)); + // result == 8 4 1 1 + data.push_back(Vertex45(Point(8, 4), 1, 1)); + // result == 8 12 -1 -1 + data.push_back(Vertex45(Point(8, 12), -1, -1)); + // result == 8 12 2 -1 + data.push_back(Vertex45(Point(8, 12), 2, -1)); + // result == 8 16 2 1 + data.push_back(Vertex45(Point(8, 16), 2, 1)); + // result == 8 16 1 1 + data.push_back(Vertex45(Point(8, 16), 1, 1)); + // result == 12 8 1 -1 + data.push_back(Vertex45(Point(12, 8), 1, -1)); + // result == 12 8 -1 1 + data.push_back(Vertex45(Point(12, 8), -1, 1)); + + data.push_back(Vertex45(Point(6, 4), 1, -1)); + data.push_back(Vertex45(Point(6, 4), 2, -1)); + data.push_back(Vertex45(Point(6, 8), -1, 1)); + data.push_back(Vertex45(Point(6, 8), 2, 1)); + data.push_back(Vertex45(Point(8, 6), -1, -1)); + data.push_back(Vertex45(Point(8, 6), 1, 1)); + + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45TilingStarHole2(stream_type& stdcout) { + stdcout << "testing polygon tiling star hole 2\n"; + Polygon45Tiling pf; + std::vector<Polygon45WithHoles> polys; + std::vector<Vertex45> data; + // result == 0 8 -1 1 + data.push_back(Vertex45(Point(0, 8), -1, 1)); + // result == 0 8 1 -1 + data.push_back(Vertex45(Point(0, 8), 1, -1)); + // result == 4 0 1 1 + data.push_back(Vertex45(Point(4, 0), 1, 1)); + // result == 4 0 2 1 + data.push_back(Vertex45(Point(4, 0), 2, 1)); + // result == 4 4 2 -1 + data.push_back(Vertex45(Point(4, 4), 2, -1)); + // result == 4 4 -1 -1 + data.push_back(Vertex45(Point(4, 4), -1, -1)); + // result == 4 12 1 1 + data.push_back(Vertex45(Point(4, 12), 1, 1)); + // result == 4 12 2 1 + data.push_back(Vertex45(Point(4, 12), 2, 1)); + // result == 4 16 2 -1 + data.push_back(Vertex45(Point(4, 16), 2, 1)); + // result == 4 16 -1 -1 + data.push_back(Vertex45(Point(4, 16), -1, -1)); + // result == 6 2 1 -1 + data.push_back(Vertex45(Point(6, 2), 1, -1)); + // result == 6 14 -1 1 + data.push_back(Vertex45(Point(6, 14), -1, 1)); + // result == 6 2 -1 1 + data.push_back(Vertex45(Point(6, 2), -1, 1)); + // result == 6 14 1 -1 + data.push_back(Vertex45(Point(6, 14), 1, -1)); + // result == 8 0 -1 -1 + data.push_back(Vertex45(Point(8, 0), -1, -1)); + // result == 8 0 2 -1 + data.push_back(Vertex45(Point(8, 0), 2, -1)); + // result == 8 4 2 1 + data.push_back(Vertex45(Point(8, 4), 2, 1)); + // result == 8 4 1 1 + data.push_back(Vertex45(Point(8, 4), 1, 1)); + // result == 8 12 -1 -1 + data.push_back(Vertex45(Point(8, 12), -1, -1)); + // result == 8 12 2 -1 + data.push_back(Vertex45(Point(8, 12), 2, -1)); + // result == 8 16 2 1 + data.push_back(Vertex45(Point(8, 16), 2, 1)); + // result == 8 16 1 1 + data.push_back(Vertex45(Point(8, 16), 1, 1)); + // result == 12 8 1 -1 + data.push_back(Vertex45(Point(12, 8), 1, -1)); + // result == 12 8 -1 1 + data.push_back(Vertex45(Point(12, 8), -1, 1)); + + data.push_back(Vertex45(Point(6, 4), 1, -1)); + data.push_back(Vertex45(Point(6, 4), 2, -1)); + data.push_back(Vertex45(Point(6, 12), -1, 1)); + data.push_back(Vertex45(Point(6, 12), 2, 1)); + data.push_back(Vertex45(Point(10, 8), -1, -1)); + data.push_back(Vertex45(Point(10, 8), 1, 1)); + + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygon45Tiling(stream_type& stdcout) { + stdcout << "testing polygon tiling\n"; + Polygon45Tiling pf; + std::vector<Polygon45WithHoles> polys; + std::vector<Vertex45> data; + + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 100), 2, -1)); + data.push_back(Vertex45(Point(0, 100), 0, -1)); + data.push_back(Vertex45(Point(100, 0), 0, -1)); + data.push_back(Vertex45(Point(100, 0), 2, -1)); + data.push_back(Vertex45(Point(100, 100), 2, 1)); + data.push_back(Vertex45(Point(100, 100), 0, 1)); + + data.push_back(Vertex45(Point(2, 2), 0, -1)); + data.push_back(Vertex45(Point(2, 2), 2, -1)); + data.push_back(Vertex45(Point(2, 10), 2, 1)); + data.push_back(Vertex45(Point(2, 10), 0, 1)); + data.push_back(Vertex45(Point(10, 2), 0, 1)); + data.push_back(Vertex45(Point(10, 2), 2, 1)); + data.push_back(Vertex45(Point(10, 10), 2, -1)); + data.push_back(Vertex45(Point(10, 10), 0, -1)); + + data.push_back(Vertex45(Point(2, 12), 0, -1)); + data.push_back(Vertex45(Point(2, 12), 2, -1)); + data.push_back(Vertex45(Point(2, 22), 2, 1)); + data.push_back(Vertex45(Point(2, 22), 0, 1)); + data.push_back(Vertex45(Point(10, 12), 0, 1)); + data.push_back(Vertex45(Point(10, 12), 2, 1)); + data.push_back(Vertex45(Point(10, 22), 2, -1)); + data.push_back(Vertex45(Point(10, 22), 0, -1)); + + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + }; + + template <typename Unit> + class PolyLine45HoleData { + public: + typedef typename polygon_45_formation<Unit>::ActiveTail45 ActiveTail45; + typedef typename ActiveTail45::iterator iterator; + + typedef polygon_45_concept geometry_type; + typedef Unit coordinate_type; + typedef point_data<Unit> Point; + typedef Point point_type; + // typedef iterator_points_to_compact<iterator, Point> compact_iterator_type; + typedef iterator iterator_type; + typedef typename coordinate_traits<Unit>::area_type area_type; + + inline PolyLine45HoleData() : p_(0) {} + inline PolyLine45HoleData(ActiveTail45* p) : p_(p) {} + //use default copy and assign + inline iterator begin() const { return p_->getTail()->begin(); } + inline iterator end() const { return p_->getTail()->end(); } + inline std::size_t size() const { return 0; } + template<class iT> + inline PolyLine45HoleData& set(iT inputBegin, iT inputEnd) { + return *this; + } + private: + ActiveTail45* p_; + }; + + template <typename Unit> + class PolyLine45PolygonData { + public: + typedef typename polygon_45_formation<Unit>::ActiveTail45 ActiveTail45; + typedef typename ActiveTail45::iterator iterator; + typedef PolyLine45HoleData<Unit> holeType; + + typedef polygon_45_with_holes_concept geometry_type; + typedef Unit coordinate_type; + typedef point_data<Unit> Point; + typedef Point point_type; + // typedef iterator_points_to_compact<iterator, Point> compact_iterator_type; + typedef iterator iterator_type; + typedef holeType hole_type; + typedef typename coordinate_traits<Unit>::area_type area_type; + class iteratorHoles { + private: + typename ActiveTail45::iteratorHoles itr_; + public: + typedef PolyLine45HoleData<Unit> holeType; + typedef holeType value_type; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + typedef const value_type* pointer; //immutable + typedef const value_type& reference; //immutable + inline iteratorHoles() : itr_() {} + inline iteratorHoles(typename ActiveTail45::iteratorHoles itr) : itr_(itr) {} + inline iteratorHoles(const iteratorHoles& that) : itr_(that.itr_) {} + inline iteratorHoles& operator=(const iteratorHoles& that) { + itr_ = that.itr_; + return *this; + } + inline bool operator==(const iteratorHoles& that) { return itr_ == that.itr_; } + inline bool operator!=(const iteratorHoles& that) { return itr_ != that.itr_; } + inline iteratorHoles& operator++() { + ++itr_; + return *this; + } + inline const iteratorHoles operator++(int) { + iteratorHoles tmp = *this; + ++(*this); + return tmp; + } + inline holeType operator*() { + return *itr_; + } + }; + typedef iteratorHoles iterator_holes_type; + + + inline PolyLine45PolygonData() : p_(0) {} + inline PolyLine45PolygonData(ActiveTail45* p) : p_(p) {} + //use default copy and assign + inline iterator begin() const { return p_->getTail()->begin(); } + inline iterator end() const { return p_->getTail()->end(); } + inline iteratorHoles begin_holes() const { return iteratorHoles(p_->getHoles().begin()); } + inline iteratorHoles end_holes() const { return iteratorHoles(p_->getHoles().end()); } + inline ActiveTail45* yield() { return p_; } + //stub out these four required functions that will not be used but are needed for the interface + inline std::size_t size_holes() const { return 0; } + inline std::size_t size() const { return 0; } + template<class iT> + inline PolyLine45PolygonData& set(iT inputBegin, iT inputEnd) { + return *this; + } + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template<class iT> + inline PolyLine45PolygonData& set_holes(iT inputBegin, iT inputEnd) { + return *this; + } + private: + ActiveTail45* p_; + }; + + template <typename T> + struct PolyLineByConcept<T, polygon_45_with_holes_concept> { typedef PolyLine45PolygonData<T> type; }; + template <typename T> + struct PolyLineByConcept<T, polygon_with_holes_concept> { typedef PolyLine45PolygonData<T> type; }; + template <typename T> + struct PolyLineByConcept<T, polygon_45_concept> { typedef PolyLine45HoleData<T> type; }; + template <typename T> + struct PolyLineByConcept<T, polygon_concept> { typedef PolyLine45HoleData<T> type; }; + + template <typename T> + struct geometry_concept<PolyLine45PolygonData<T> > { typedef polygon_45_with_holes_concept type; }; + template <typename T> + struct geometry_concept<PolyLine45HoleData<T> > { typedef polygon_45_concept type; }; + +} +} +#endif diff --git a/boost/polygon/detail/polygon_45_set_view.hpp b/boost/polygon/detail/polygon_45_set_view.hpp new file mode 100644 index 0000000000..34423862b6 --- /dev/null +++ b/boost/polygon/detail/polygon_45_set_view.hpp @@ -0,0 +1,378 @@ +/* + 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_POLYGON_45_SET_VIEW_HPP +#define BOOST_POLYGON_POLYGON_45_SET_VIEW_HPP +namespace boost { namespace polygon{ + + template <typename ltype, typename rtype, int op_type> + class polygon_45_set_view; + + template <typename ltype, typename rtype, int op_type> + struct polygon_45_set_traits<polygon_45_set_view<ltype, rtype, op_type> > { + typedef typename polygon_45_set_view<ltype, rtype, op_type>::coordinate_type coordinate_type; + typedef typename polygon_45_set_view<ltype, rtype, op_type>::iterator_type iterator_type; + typedef typename polygon_45_set_view<ltype, rtype, op_type>::operator_arg_type operator_arg_type; + + static inline iterator_type begin(const polygon_45_set_view<ltype, rtype, op_type>& polygon_45_set); + static inline iterator_type end(const polygon_45_set_view<ltype, rtype, op_type>& polygon_45_set); + + template <typename input_iterator_type> + static inline void set(polygon_45_set_view<ltype, rtype, op_type>& polygon_45_set, + input_iterator_type input_begin, input_iterator_type input_end); + + static inline bool clean(const polygon_45_set_view<ltype, rtype, op_type>& polygon_45_set); + + }; + + template <typename value_type, typename ltype, typename rtype, int op_type> + struct compute_45_set_value { + static + void value(value_type& output_, const ltype& lvalue_, const rtype& rvalue_) { + output_.set(polygon_45_set_traits<ltype>::begin(lvalue_), + polygon_45_set_traits<ltype>::end(lvalue_)); + value_type rinput_; + rinput_.set(polygon_45_set_traits<rtype>::begin(rvalue_), + polygon_45_set_traits<rtype>::end(rvalue_)); +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op_type == 0) + output_ |= rinput_; + else if(op_type == 1) + output_ &= rinput_; + else if(op_type == 2) + output_ ^= rinput_; + else + output_ -= rinput_; +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + } + }; + + template <typename value_type, typename ltype, typename rcoord, int op_type> + struct compute_45_set_value<value_type, ltype, polygon_45_set_data<rcoord>, op_type> { + static + void value(value_type& output_, const ltype& lvalue_, const polygon_45_set_data<rcoord>& rvalue_) { + output_.set(polygon_45_set_traits<ltype>::begin(lvalue_), + polygon_45_set_traits<ltype>::end(lvalue_)); +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op_type == 0) + output_ |= rvalue_; + else if(op_type == 1) + output_ &= rvalue_; + else if(op_type == 2) + output_ ^= rvalue_; + else + output_ -= rvalue_; +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + } + }; + + template <typename ltype, typename rtype, int op_type> + class polygon_45_set_view { + public: + typedef typename polygon_45_set_traits<ltype>::coordinate_type coordinate_type; + typedef polygon_45_set_data<coordinate_type> value_type; + typedef typename value_type::iterator_type iterator_type; + typedef polygon_45_set_view operator_arg_type; + private: + const ltype& lvalue_; + const rtype& rvalue_; + mutable value_type output_; + mutable bool evaluated_; + + polygon_45_set_view& operator=(const polygon_45_set_view&); + public: + polygon_45_set_view(const ltype& lvalue, + const rtype& rvalue ) : + lvalue_(lvalue), rvalue_(rvalue), output_(), evaluated_(false) {} + + // get iterator to begin vertex data + public: + const value_type& value() const { + if(!evaluated_) { + evaluated_ = true; + compute_45_set_value<value_type, ltype, rtype, op_type>::value(output_, lvalue_, rvalue_); + } + return output_; + } + public: + iterator_type begin() const { return value().begin(); } + iterator_type end() const { return value().end(); } + + bool dirty() const { return value().dirty(); } //result of a boolean is clean + bool sorted() const { return value().sorted(); } //result of a boolean is sorted + + // template <typename input_iterator_type> + // void set(input_iterator_type input_begin, input_iterator_type input_end, + // orientation_2d orient) const { + // orient_ = orient; + // output_.clear(); + // output_.insert(output_.end(), input_begin, input_end); + // gtlsort(output_.begin(), output_.end()); + // } + }; + + template <typename ltype, typename rtype, int op_type> + typename polygon_45_set_traits<polygon_45_set_view<ltype, rtype, op_type> >::iterator_type + polygon_45_set_traits<polygon_45_set_view<ltype, rtype, op_type> >:: + begin(const polygon_45_set_view<ltype, rtype, op_type>& polygon_45_set) { + return polygon_45_set.begin(); + } + template <typename ltype, typename rtype, int op_type> + typename polygon_45_set_traits<polygon_45_set_view<ltype, rtype, op_type> >::iterator_type + polygon_45_set_traits<polygon_45_set_view<ltype, rtype, op_type> >:: + end(const polygon_45_set_view<ltype, rtype, op_type>& polygon_45_set) { + return polygon_45_set.end(); + } + template <typename ltype, typename rtype, int op_type> + bool polygon_45_set_traits<polygon_45_set_view<ltype, rtype, op_type> >:: + clean(const polygon_45_set_view<ltype, rtype, op_type>& polygon_45_set) { + return polygon_45_set.value().clean(); } + + template <typename geometry_type_1, typename geometry_type_2, int op_type> + geometry_type_1& self_assignment_boolean_op_45(geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { + typedef geometry_type_1 ltype; + typedef geometry_type_2 rtype; + typedef typename polygon_45_set_traits<ltype>::coordinate_type coordinate_type; + typedef polygon_45_set_data<coordinate_type> value_type; + value_type output_; + value_type rinput_; + output_.set(polygon_45_set_traits<ltype>::begin(lvalue_), + polygon_45_set_traits<ltype>::end(lvalue_)); + rinput_.set(polygon_45_set_traits<rtype>::begin(rvalue_), + polygon_45_set_traits<rtype>::end(rvalue_)); +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op_type == 0) + output_ |= rinput_; + else if(op_type == 1) + output_ &= rinput_; + else if(op_type == 2) + output_ ^= rinput_; + else + output_ -= rinput_; +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + polygon_45_set_mutable_traits<geometry_type_1>::set(lvalue_, output_.begin(), output_.end()); + return lvalue_; + } + + template <typename concept_type> + struct fracture_holes_option_by_type { + static const bool value = true; + }; + template <> + struct fracture_holes_option_by_type<polygon_45_with_holes_concept> { + static const bool value = false; + }; + template <> + struct fracture_holes_option_by_type<polygon_with_holes_concept> { + static const bool value = false; + }; + + template <typename ltype, typename rtype, int op_type> + struct geometry_concept<polygon_45_set_view<ltype, rtype, op_type> > { typedef polygon_45_set_concept type; }; + + namespace operators { + struct y_ps45_b : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_4< y_ps45_b, + typename is_polygon_45_or_90_set_type<geometry_type_1>::type, + typename is_polygon_45_or_90_set_type<geometry_type_2>::type, + typename is_either_polygon_45_set_type<geometry_type_1, geometry_type_2>::type>::type, + polygon_45_set_view<geometry_type_1, geometry_type_2, 0> >::type + operator|(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_45_set_view<geometry_type_1, geometry_type_2, 0> + (lvalue, rvalue); + } + + struct y_ps45_p : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_4< y_ps45_p, + typename gtl_if<typename is_polygon_45_or_90_set_type<geometry_type_1>::type>::type, + typename gtl_if<typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, + typename gtl_if<typename is_either_polygon_45_set_type<geometry_type_1, geometry_type_2>::type>::type>::type, + polygon_45_set_view<geometry_type_1, geometry_type_2, 0> >::type + operator+(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_45_set_view<geometry_type_1, geometry_type_2, 0> + (lvalue, rvalue); + } + + struct y_ps45_s : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_4< y_ps45_s, typename is_polygon_45_or_90_set_type<geometry_type_1>::type, + typename is_polygon_45_or_90_set_type<geometry_type_2>::type, + typename is_either_polygon_45_set_type<geometry_type_1, geometry_type_2>::type>::type, + polygon_45_set_view<geometry_type_1, geometry_type_2, 1> >::type + operator*(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_45_set_view<geometry_type_1, geometry_type_2, 1> + (lvalue, rvalue); + } + + struct y_ps45_a : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_4< y_ps45_a, typename is_polygon_45_or_90_set_type<geometry_type_1>::type, + typename is_polygon_45_or_90_set_type<geometry_type_2>::type, + typename is_either_polygon_45_set_type<geometry_type_1, geometry_type_2>::type>::type, + polygon_45_set_view<geometry_type_1, geometry_type_2, 1> >::type + operator&(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_45_set_view<geometry_type_1, geometry_type_2, 1> + (lvalue, rvalue); + } + + struct y_ps45_x : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_4< y_ps45_x, typename is_polygon_45_or_90_set_type<geometry_type_1>::type, + typename is_polygon_45_or_90_set_type<geometry_type_2>::type, + typename is_either_polygon_45_set_type<geometry_type_1, geometry_type_2>::type>::type, + polygon_45_set_view<geometry_type_1, geometry_type_2, 2> >::type + operator^(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_45_set_view<geometry_type_1, geometry_type_2, 2> + (lvalue, rvalue); + } + + struct y_ps45_m : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_4< y_ps45_m, + typename gtl_if<typename is_polygon_45_or_90_set_type<geometry_type_1>::type>::type, + typename gtl_if<typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, + typename gtl_if<typename is_either_polygon_45_set_type<geometry_type_1, geometry_type_2>::type>::type>::type, + polygon_45_set_view<geometry_type_1, geometry_type_2, 3> >::type + operator-(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_45_set_view<geometry_type_1, geometry_type_2, 3> + (lvalue, rvalue); + } + + struct y_ps45_pe : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_4<y_ps45_pe, typename is_mutable_polygon_45_set_type<geometry_type_1>::type, gtl_yes, + typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator+=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op_45<geometry_type_1, geometry_type_2, 0>(lvalue, rvalue); + } + + struct y_ps45_be : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3<y_ps45_be, typename is_mutable_polygon_45_set_type<geometry_type_1>::type, + typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator|=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op_45<geometry_type_1, geometry_type_2, 0>(lvalue, rvalue); + } + + struct y_ps45_se : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3< y_ps45_se, + typename is_mutable_polygon_45_set_type<geometry_type_1>::type, + typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator*=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op_45<geometry_type_1, geometry_type_2, 1>(lvalue, rvalue); + } + + struct y_ps45_ae : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3<y_ps45_ae, typename is_mutable_polygon_45_set_type<geometry_type_1>::type, + typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator&=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op_45<geometry_type_1, geometry_type_2, 1>(lvalue, rvalue); + } + + struct y_ps45_xe : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< + typename gtl_and_3<y_ps45_xe, typename is_mutable_polygon_45_set_type<geometry_type_1>::type, + typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator^=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op_45<geometry_type_1, geometry_type_2, 2>(lvalue, rvalue); + } + + struct y_ps45_me : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3<y_ps45_me, typename is_mutable_polygon_45_set_type<geometry_type_1>::type, + typename is_polygon_45_or_90_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator-=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op_45<geometry_type_1, geometry_type_2, 3>(lvalue, rvalue); + } + + struct y_ps45_rpe : gtl_yes {}; + + template <typename geometry_type_1, typename coordinate_type_1> + typename enable_if< typename gtl_and_3< y_ps45_rpe, typename is_mutable_polygon_45_set_type<geometry_type_1>::type, + typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, + coordinate_concept>::type>::type, + geometry_type_1>::type & + operator+=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { + return resize(lvalue, rvalue); + } + + struct y_ps45_rme : gtl_yes {}; + + template <typename geometry_type_1, typename coordinate_type_1> + typename enable_if< typename gtl_and_3<y_ps45_rme, typename gtl_if<typename is_mutable_polygon_45_set_type<geometry_type_1>::type>::type, + typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, + coordinate_concept>::type>::type, + geometry_type_1>::type & + operator-=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { + return resize(lvalue, -rvalue); + } + + struct y_ps45_rp : gtl_yes {}; + + template <typename geometry_type_1, typename coordinate_type_1> + typename enable_if< typename gtl_and_3<y_ps45_rp, typename gtl_if<typename is_mutable_polygon_45_set_type<geometry_type_1>::type>::type, + typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, + coordinate_concept>::type> + ::type, geometry_type_1>::type + operator+(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { + geometry_type_1 retval(lvalue); + retval += rvalue; + return retval; + } + + struct y_ps45_rm : gtl_yes {}; + + template <typename geometry_type_1, typename coordinate_type_1> + typename enable_if< typename gtl_and_3<y_ps45_rm, typename gtl_if<typename is_mutable_polygon_45_set_type<geometry_type_1>::type>::type, + typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, + coordinate_concept>::type> + ::type, geometry_type_1>::type + operator-(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { + geometry_type_1 retval(lvalue); + retval -= rvalue; + return retval; + } + } +} +} +#endif + diff --git a/boost/polygon/detail/polygon_45_touch.hpp b/boost/polygon/detail/polygon_45_touch.hpp new file mode 100644 index 0000000000..e50912ac9b --- /dev/null +++ b/boost/polygon/detail/polygon_45_touch.hpp @@ -0,0 +1,236 @@ +/* + 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_POLYGON_45_TOUCH_HPP +#define BOOST_POLYGON_POLYGON_45_TOUCH_HPP +namespace boost { namespace polygon{ + + template <typename Unit> + struct polygon_45_touch { + + typedef point_data<Unit> Point; + typedef typename coordinate_traits<Unit>::manhattan_area_type LongUnit; + + template <typename property_map> + static inline void merge_property_maps(property_map& mp, const property_map& mp2, bool subtract = false) { + property_map newmp; + newmp.reserve(mp.size() + mp2.size()); + std::size_t i = 0; + std::size_t j = 0; + while(i != mp.size() && j != mp2.size()) { + if(mp[i].first < mp2[j].first) { + newmp.push_back(mp[i]); + ++i; + } else if(mp[i].first > mp2[j].first) { + newmp.push_back(mp2[j]); + if(subtract) newmp.back().second *= -1; + ++j; + } else { + int count = mp[i].second; + if(subtract) count -= mp2[j].second; + else count += mp2[j].second; + if(count) { + newmp.push_back(mp[i]); + newmp.back().second = count; + } + ++i; + ++j; + } + } + while(i != mp.size()) { + newmp.push_back(mp[i]); + ++i; + } + while(j != mp2.size()) { + newmp.push_back(mp2[j]); + if(subtract) newmp.back().second *= -1; + ++j; + } + mp.swap(newmp); + } + + class CountTouch { + public: + inline CountTouch() : counts() {} + //inline CountTouch(int count) { counts[0] = counts[1] = count; } + //inline CountTouch(int count1, int count2) { counts[0] = count1; counts[1] = count2; } + inline CountTouch(const CountTouch& count) : counts(count.counts) {} + inline bool operator==(const CountTouch& count) const { return counts == count.counts; } + inline bool operator!=(const CountTouch& count) const { return !((*this) == count); } + //inline CountTouch& operator=(int count) { counts[0] = counts[1] = count; return *this; } + inline CountTouch& operator=(const CountTouch& count) { counts = count.counts; return *this; } + inline int& operator[](int index) { + std::vector<std::pair<int, int> >::iterator itr = lower_bound(counts.begin(), counts.end(), std::make_pair(index, int(0))); + if(itr != counts.end() && itr->first == index) { + return itr->second; + } + itr = counts.insert(itr, std::make_pair(index, int(0))); + return itr->second; + } +// inline int operator[](int index) const { +// std::vector<std::pair<int, int> >::const_iterator itr = counts.begin(); +// for( ; itr != counts.end() && itr->first <= index; ++itr) { +// if(itr->first == index) { +// return itr->second; +// } +// } +// return 0; +// } + inline CountTouch& operator+=(const CountTouch& count){ + merge_property_maps(counts, count.counts, false); + return *this; + } + inline CountTouch& operator-=(const CountTouch& count){ + merge_property_maps(counts, count.counts, true); + return *this; + } + inline CountTouch operator+(const CountTouch& count) const { + return CountTouch(*this)+=count; + } + inline CountTouch operator-(const CountTouch& count) const { + return CountTouch(*this)-=count; + } + inline CountTouch invert() const { + CountTouch retval; + retval -= *this; + return retval; + } + std::vector<std::pair<int, int> > counts; + }; + + typedef std::pair<std::pair<Unit, std::map<Unit, std::set<int> > >, std::map<int, std::set<int> > > map_graph_o; + typedef std::pair<std::pair<Unit, std::map<Unit, std::set<int> > >, std::vector<std::set<int> > > vector_graph_o; + + template <typename cT> + static void process_previous_x(cT& output) { + std::map<Unit, std::set<int> >& y_prop_map = output.first.second; + for(typename std::map<Unit, std::set<int> >::iterator itr = y_prop_map.begin(); + itr != y_prop_map.end(); ++itr) { + for(std::set<int>::iterator inner_itr = itr->second.begin(); + inner_itr != itr->second.end(); ++inner_itr) { + std::set<int>& output_edges = (*(output.second))[*inner_itr]; + std::set<int>::iterator inner_inner_itr = inner_itr; + ++inner_inner_itr; + for( ; inner_inner_itr != itr->second.end(); ++inner_inner_itr) { + output_edges.insert(output_edges.end(), *inner_inner_itr); + std::set<int>& output_edges_2 = (*(output.second))[*inner_inner_itr]; + output_edges_2.insert(output_edges_2.end(), *inner_itr); + } + } + } + y_prop_map.clear(); + } + + struct touch_45_output_functor { + template <typename cT> + void operator()(cT& output, const CountTouch& count1, const CountTouch& count2, + const Point& pt, int , direction_1d ) { + Unit& x = output.first.first; + std::map<Unit, std::set<int> >& y_prop_map = output.first.second; + if(pt.x() != x) process_previous_x(output); + x = pt.x(); + std::set<int>& output_set = y_prop_map[pt.y()]; + for(std::vector<std::pair<int, int> >::const_iterator itr1 = count1.counts.begin(); + itr1 != count1.counts.end(); ++itr1) { + if(itr1->second > 0) { + output_set.insert(output_set.end(), itr1->first); + } + } + for(std::vector<std::pair<int, int> >::const_iterator itr2 = count2.counts.begin(); + itr2 != count2.counts.end(); ++itr2) { + if(itr2->second > 0) { + output_set.insert(output_set.end(), itr2->first); + } + } + } + }; + typedef typename std::pair<Point, + typename boolean_op_45<Unit>::template Scan45CountT<CountTouch> > Vertex45Compact; + typedef std::vector<Vertex45Compact> TouchSetData; + + struct lessVertex45Compact { + bool operator()(const Vertex45Compact& l, const Vertex45Compact& r) { + return l.first < r.first; + } + }; + +// template <typename TSD> +// static void print_tsd(TSD& tsd) { +// for(std::size_t i = 0; i < tsd.size(); ++i) { +// std::cout << tsd[i].first << ": "; +// for(unsigned int r = 0; r < 4; ++r) { +// std::cout << r << " { "; +// for(std::vector<std::pair<int, int> >::iterator itr = tsd[i].second[r].counts.begin(); +// itr != tsd[i].second[r].counts.end(); ++itr) { +// std::cout << itr->first << "," << itr->second << " "; +// } std::cout << "} "; +// } +// } std::cout << std::endl; +// } + +// template <typename T> +// static void print_scanline(T& t) { +// for(typename T::iterator itr = t.begin(); itr != t.end(); ++itr) { +// std::cout << itr->x << "," << itr->y << " " << itr->rise << " "; +// for(std::vector<std::pair<int, int> >::iterator itr2 = itr->count.counts.begin(); +// itr2 != itr->count.counts.end(); ++itr2) { +// std::cout << itr2->first << ":" << itr2->second << " "; +// } std::cout << std::endl; +// } +// } + + template <typename graph_type> + static void performTouch(graph_type& graph, TouchSetData& tsd) { + + gtlsort(tsd.begin(), tsd.end(), lessVertex45Compact()); + typedef std::vector<std::pair<Point, typename boolean_op_45<Unit>::template Scan45CountT<CountTouch> > > TSD; + TSD tsd_; + tsd_.reserve(tsd.size()); + for(typename TouchSetData::iterator itr = tsd.begin(); itr != tsd.end(); ) { + typename TouchSetData::iterator itr2 = itr; + ++itr2; + for(; itr2 != tsd.end() && itr2->first == itr->first; ++itr2) { + (itr->second) += (itr2->second); //accumulate + } + tsd_.push_back(std::make_pair(itr->first, itr->second)); + itr = itr2; + } + std::pair<std::pair<Unit, std::map<Unit, std::set<int> > >, graph_type*> output + (std::make_pair(std::make_pair((std::numeric_limits<Unit>::max)(), std::map<Unit, std::set<int> >()), &graph)); + typename boolean_op_45<Unit>::template Scan45<CountTouch, touch_45_output_functor> scanline; + for(typename TSD::iterator itr = tsd_.begin(); itr != tsd_.end(); ) { + typename TSD::iterator itr2 = itr; + ++itr2; + while(itr2 != tsd_.end() && itr2->first.x() == itr->first.x()) { + ++itr2; + } + scanline.scan(output, itr, itr2); + itr = itr2; + } + process_previous_x(output); + } + + template <typename iT> + static void populateTouchSetData(TouchSetData& tsd, iT begin, iT end, int nodeCount) { + for( ; begin != end; ++begin) { + Vertex45Compact vertex; + vertex.first = typename Vertex45Compact::first_type(begin->pt.x() * 2, begin->pt.y() * 2); + tsd.push_back(vertex); + for(unsigned int i = 0; i < 4; ++i) { + if(begin->count[i]) { + tsd.back().second[i][nodeCount] += begin->count[i]; + } + } + } + } + + }; + + +} +} +#endif diff --git a/boost/polygon/detail/polygon_90_set_view.hpp b/boost/polygon/detail/polygon_90_set_view.hpp new file mode 100644 index 0000000000..53beec8da1 --- /dev/null +++ b/boost/polygon/detail/polygon_90_set_view.hpp @@ -0,0 +1,491 @@ +/* + 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_POLYGON_90_SET_VIEW_HPP +#define BOOST_POLYGON_POLYGON_90_SET_VIEW_HPP +namespace boost { namespace polygon{ + struct operator_provides_storage {}; + struct operator_requires_copy {}; + + template <typename value_type, typename arg_type> + inline void insert_into_view_arg(value_type& dest, const arg_type& arg, orientation_2d orient); + + template <typename ltype, typename rtype, typename op_type> + class polygon_90_set_view; + + template <typename ltype, typename rtype, typename op_type> + struct polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> > { + typedef typename polygon_90_set_view<ltype, rtype, op_type>::coordinate_type coordinate_type; + typedef typename polygon_90_set_view<ltype, rtype, op_type>::iterator_type iterator_type; + typedef typename polygon_90_set_view<ltype, rtype, op_type>::operator_arg_type operator_arg_type; + + static inline iterator_type begin(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set); + static inline iterator_type end(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set); + + static inline orientation_2d orient(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set); + + static inline bool clean(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set); + + static inline bool sorted(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set); + }; + + template <typename value_type, typename ltype, typename rtype, typename op_type> + struct compute_90_set_value { + static + void value(value_type& output_, const ltype& lvalue_, const rtype& rvalue_, orientation_2d orient_) { + value_type linput_(orient_); + value_type rinput_(orient_); + orientation_2d orient_l = polygon_90_set_traits<ltype>::orient(lvalue_); + orientation_2d orient_r = polygon_90_set_traits<rtype>::orient(rvalue_); + //std::cout << "compute_90_set_value-0 orientations (left, right, out):\t" << orient_l.to_int() + // << "," << orient_r.to_int() << "," << orient_.to_int() << std::endl; + insert_into_view_arg(linput_, lvalue_, orient_l); + insert_into_view_arg(rinput_, rvalue_, orient_r); + output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount<op_type>()); + } + }; + + template <typename value_type, typename lcoord, typename rcoord, typename op_type> + struct compute_90_set_value<value_type, polygon_90_set_data<lcoord>, polygon_90_set_data<rcoord>, op_type> { + static + void value(value_type& output_, const polygon_90_set_data<lcoord>& lvalue_, + const polygon_90_set_data<rcoord>& rvalue_, orientation_2d orient_) { + orientation_2d orient_l = lvalue_.orient(); + orientation_2d orient_r = rvalue_.orient(); + value_type linput_(orient_); + value_type rinput_(orient_); + //std::cout << "compute_90_set_value-1 orientations (left, right, out):\t" << orient_l.to_int() + // << "," << orient_r.to_int() << "," << orient_.to_int() << std::endl; + if((orient_ == orient_l) && (orient_== orient_r)){ // assume that most of the time this condition is met + lvalue_.sort(); + rvalue_.sort(); + output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), + rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount<op_type>()); + }else if((orient_ != orient_l) && (orient_!= orient_r)){ // both the orientations are not equal to input + // easier way is to ignore the input orientation and use the input data's orientation, but not done so + insert_into_view_arg(linput_, lvalue_, orient_l); + insert_into_view_arg(rinput_, rvalue_, orient_r); + output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount<op_type>()); + }else if(orient_ != orient_l){ // left hand side orientation is different + insert_into_view_arg(linput_, lvalue_, orient_l); + rvalue_.sort(); + output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), + rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount<op_type>()); + } else if(orient_ != orient_r){ // right hand side orientation is different + insert_into_view_arg(rinput_, rvalue_, orient_r); + lvalue_.sort(); + output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount<op_type>()); + } + } + }; + + template <typename value_type, typename lcoord, typename rtype, typename op_type> + struct compute_90_set_value<value_type, polygon_90_set_data<lcoord>, rtype, op_type> { + static + void value(value_type& output_, const polygon_90_set_data<lcoord>& lvalue_, + const rtype& rvalue_, orientation_2d orient_) { + value_type rinput_(orient_); + lvalue_.sort(); + orientation_2d orient_r = polygon_90_set_traits<rtype>::orient(rvalue_); + //std::cout << "compute_90_set_value-2 orientations (right, out):\t" << orient_r.to_int() + // << "," << orient_.to_int() << std::endl; + insert_into_view_arg(rinput_, rvalue_, orient_r); + output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount<op_type>()); + } + }; + + template <typename value_type, typename ltype, typename rcoord, typename op_type> + struct compute_90_set_value<value_type, ltype, polygon_90_set_data<rcoord>, op_type> { + static + void value(value_type& output_, const ltype& lvalue_, + const polygon_90_set_data<rcoord>& rvalue_, orientation_2d orient_) { + value_type linput_(orient_); + orientation_2d orient_l = polygon_90_set_traits<ltype>::orient(lvalue_); + insert_into_view_arg(linput_, lvalue_, orient_l); + rvalue_.sort(); + //std::cout << "compute_90_set_value-3 orientations (left, out):\t" << orient_l.to_int() + // << "," << orient_.to_int() << std::endl; + + output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), + rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount<op_type>()); + } + }; + + template <typename ltype, typename rtype, typename op_type> + class polygon_90_set_view { + public: + typedef typename polygon_90_set_traits<ltype>::coordinate_type coordinate_type; + typedef polygon_90_set_data<coordinate_type> value_type; + typedef typename value_type::iterator_type iterator_type; + typedef polygon_90_set_view operator_arg_type; + private: + const ltype& lvalue_; + const rtype& rvalue_; + orientation_2d orient_; + op_type op_; + mutable value_type output_; + mutable bool evaluated_; + polygon_90_set_view& operator=(const polygon_90_set_view&); + public: + polygon_90_set_view(const ltype& lvalue, + const rtype& rvalue, + orientation_2d orient, + op_type op) : + lvalue_(lvalue), rvalue_(rvalue), orient_(orient), op_(op), output_(orient), evaluated_(false) {} + + // get iterator to begin vertex data + private: + const value_type& value() const { + if(!evaluated_) { + evaluated_ = true; + compute_90_set_value<value_type, ltype, rtype, op_type>::value(output_, lvalue_, rvalue_, orient_); + } + return output_; + } + public: + iterator_type begin() const { return value().begin(); } + iterator_type end() const { return value().end(); } + + orientation_2d orient() const { return orient_; } + bool dirty() const { return false; } //result of a boolean is clean + bool sorted() const { return true; } //result of a boolean is sorted + +// template <typename input_iterator_type> +// void set(input_iterator_type input_begin, input_iterator_type input_end, +// orientation_2d orient) const { +// orient_ = orient; +// output_.clear(); +// output_.insert(output_.end(), input_begin, input_end); +// gtlsort(output_.begin(), output_.end()); +// } + void sort() const {} //is always sorted + }; + + template <typename ltype, typename rtype, typename op_type> + struct geometry_concept<polygon_90_set_view<ltype, rtype, op_type> > { + typedef polygon_90_set_concept type; + }; + + template <typename ltype, typename rtype, typename op_type> + typename polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >::iterator_type + polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >:: + begin(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set) { + return polygon_set.begin(); + } + template <typename ltype, typename rtype, typename op_type> + typename polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >::iterator_type + polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >:: + end(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set) { + return polygon_set.end(); + } +// template <typename ltype, typename rtype, typename op_type> +// template <typename input_iterator_type> +// void polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >:: +// set(polygon_90_set_view<ltype, rtype, op_type>& polygon_set, +// input_iterator_type input_begin, input_iterator_type input_end, +// orientation_2d orient) { +// polygon_set.set(input_begin, input_end, orient); +// } + template <typename ltype, typename rtype, typename op_type> + orientation_2d polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >:: + orient(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set) { + return polygon_set.orient(); } + template <typename ltype, typename rtype, typename op_type> + bool polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >:: + clean(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set) { + return true; } + template <typename ltype, typename rtype, typename op_type> + bool polygon_90_set_traits<polygon_90_set_view<ltype, rtype, op_type> >:: + sorted(const polygon_90_set_view<ltype, rtype, op_type>& polygon_set) { + return true; } + + template <typename value_type, typename arg_type> + inline void insert_into_view_arg(value_type& dest, const arg_type& arg, orientation_2d orient) { + typedef typename polygon_90_set_traits<arg_type>::iterator_type literator; + literator itr1, itr2; + itr1 = polygon_90_set_traits<arg_type>::begin(arg); + itr2 = polygon_90_set_traits<arg_type>::end(arg); + dest.insert(itr1, itr2, orient); + dest.sort(); + } + + template <typename T> + template <typename ltype, typename rtype, typename op_type> + inline polygon_90_set_data<T>& polygon_90_set_data<T>::operator=(const polygon_90_set_view<ltype, rtype, op_type>& that) { + set(that.begin(), that.end(), that.orient()); + dirty_ = false; + unsorted_ = false; + return *this; + } + + template <typename T> + template <typename ltype, typename rtype, typename op_type> + inline polygon_90_set_data<T>::polygon_90_set_data(const polygon_90_set_view<ltype, rtype, op_type>& that) : + orient_(that.orient()), data_(that.begin(), that.end()), dirty_(false), unsorted_(false) {} + + template <typename geometry_type_1, typename geometry_type_2> + struct self_assign_operator_lvalue { + typedef geometry_type_1& type; + }; + + template <typename type_1, typename type_2> + struct by_value_binary_operator { + typedef type_1 type; + }; + + template <typename geometry_type_1, typename geometry_type_2, typename op_type> + geometry_type_1& self_assignment_boolean_op(geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { + typedef geometry_type_1 ltype; + typedef geometry_type_2 rtype; + typedef typename polygon_90_set_traits<ltype>::coordinate_type coordinate_type; + typedef polygon_90_set_data<coordinate_type> value_type; + orientation_2d orient_ = polygon_90_set_traits<ltype>::orient(lvalue_); + //BM: rvalue_ data set may have its own orientation for scanline + orientation_2d orient_r = polygon_90_set_traits<rtype>::orient(rvalue_); + //std::cout << "self-assignment boolean-op (left, right, out):\t" << orient_.to_int() + // << "," << orient_r.to_int() << "," << orient_.to_int() << std::endl; + value_type linput_(orient_); + // BM: the rinput_ set's (that stores the rvalue_ dataset polygons) scanline orientation is *forced* + // to be same as linput + value_type rinput_(orient_); + //BM: The output dataset's scanline orient is set as equal to first input dataset's (lvalue_) orientation + value_type output_(orient_); + insert_into_view_arg(linput_, lvalue_, orient_); + // BM: The last argument orient_r is the user initialized scanline orientation for rvalue_ data set. + // But since rinput (see above) is initialized to scanline orientation consistent with the lvalue_ + // data set, this insertion operation will change the incoming rvalue_ dataset's scanline orientation + insert_into_view_arg(rinput_, rvalue_, orient_r); + // BM: boolean operation and output uses lvalue_ dataset's scanline orientation. + output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount<op_type>()); + polygon_90_set_mutable_traits<geometry_type_1>::set(lvalue_, output_.begin(), output_.end(), orient_); + return lvalue_; + } + + namespace operators { + struct y_ps90_b : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3< y_ps90_b, + typename is_polygon_90_set_type<geometry_type_1>::type, + typename is_polygon_90_set_type<geometry_type_2>::type>::type, + polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryOr> >::type + operator|(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryOr> + (lvalue, rvalue, + polygon_90_set_traits<geometry_type_1>::orient(lvalue), + boolean_op::BinaryOr()); + } + + struct y_ps90_p : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< + typename gtl_and_3< y_ps90_p, + typename gtl_if<typename is_polygon_90_set_type<geometry_type_1>::type>::type, + typename gtl_if<typename is_polygon_90_set_type<geometry_type_2>::type>::type>::type, + polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryOr> >::type + operator+(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryOr> + (lvalue, rvalue, + polygon_90_set_traits<geometry_type_1>::orient(lvalue), + boolean_op::BinaryOr()); + } + + struct y_ps90_s : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3< y_ps90_s, + typename is_polygon_90_set_type<geometry_type_1>::type, + typename is_polygon_90_set_type<geometry_type_2>::type>::type, + polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryAnd> >::type + operator*(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryAnd> + (lvalue, rvalue, + polygon_90_set_traits<geometry_type_1>::orient(lvalue), + boolean_op::BinaryAnd()); + } + + struct y_ps90_a : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3< y_ps90_a, + typename is_polygon_90_set_type<geometry_type_1>::type, + typename is_polygon_90_set_type<geometry_type_2>::type>::type, + polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryAnd> >::type + operator&(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryAnd> + (lvalue, rvalue, + polygon_90_set_traits<geometry_type_1>::orient(lvalue), + boolean_op::BinaryAnd()); + } + + struct y_ps90_x : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3< y_ps90_x, + typename is_polygon_90_set_type<geometry_type_1>::type, + typename is_polygon_90_set_type<geometry_type_2>::type>::type, + polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryXor> >::type + operator^(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryXor> + (lvalue, rvalue, + polygon_90_set_traits<geometry_type_1>::orient(lvalue), + boolean_op::BinaryXor()); + } + + struct y_ps90_m : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3< y_ps90_m, + typename gtl_if<typename is_polygon_90_set_type<geometry_type_1>::type>::type, + typename gtl_if<typename is_polygon_90_set_type<geometry_type_2>::type>::type>::type, + polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryNot> >::type + operator-(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_90_set_view<geometry_type_1, geometry_type_2, boolean_op::BinaryNot> + (lvalue, rvalue, + polygon_90_set_traits<geometry_type_1>::orient(lvalue), + boolean_op::BinaryNot()); + } + + struct y_ps90_pe : gtl_yes {}; + + template <typename coordinate_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and< y_ps90_pe, typename is_polygon_90_set_type<geometry_type_2>::type>::type, + polygon_90_set_data<coordinate_type_1> >::type & + operator+=(polygon_90_set_data<coordinate_type_1>& lvalue, const geometry_type_2& rvalue) { + lvalue.insert(polygon_90_set_traits<geometry_type_2>::begin(rvalue), polygon_90_set_traits<geometry_type_2>::end(rvalue), + polygon_90_set_traits<geometry_type_2>::orient(rvalue)); + return lvalue; + } + + struct y_ps90_be : gtl_yes {}; + // + template <typename coordinate_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and< y_ps90_be, typename is_polygon_90_set_type<geometry_type_2>::type>::type, + polygon_90_set_data<coordinate_type_1> >::type & + operator|=(polygon_90_set_data<coordinate_type_1>& lvalue, const geometry_type_2& rvalue) { + return lvalue += rvalue; + } + + struct y_ps90_pe2 : gtl_yes {}; + + //normal self assignment boolean operations + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3< y_ps90_pe2, typename is_mutable_polygon_90_set_type<geometry_type_1>::type, + typename is_polygon_90_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator+=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op<geometry_type_1, geometry_type_2, boolean_op::BinaryOr>(lvalue, rvalue); + } + + struct y_ps90_be2 : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3<y_ps90_be2, typename is_mutable_polygon_90_set_type<geometry_type_1>::type, + typename is_polygon_90_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator|=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op<geometry_type_1, geometry_type_2, boolean_op::BinaryOr>(lvalue, rvalue); + } + + struct y_ps90_se : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3<y_ps90_se, typename is_mutable_polygon_90_set_type<geometry_type_1>::type, + typename is_polygon_90_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator*=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op<geometry_type_1, geometry_type_2, boolean_op::BinaryAnd>(lvalue, rvalue); + } + + struct y_ps90_ae : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3<y_ps90_ae, typename is_mutable_polygon_90_set_type<geometry_type_1>::type, + typename is_polygon_90_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator&=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op<geometry_type_1, geometry_type_2, boolean_op::BinaryAnd>(lvalue, rvalue); + } + + struct y_ps90_xe : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3<y_ps90_xe, typename is_mutable_polygon_90_set_type<geometry_type_1>::type, + typename is_polygon_90_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator^=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op<geometry_type_1, geometry_type_2, boolean_op::BinaryXor>(lvalue, rvalue); + } + + struct y_ps90_me : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3< y_ps90_me, typename is_mutable_polygon_90_set_type<geometry_type_1>::type, + typename is_polygon_90_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator-=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op<geometry_type_1, geometry_type_2, boolean_op::BinaryNot>(lvalue, rvalue); + } + + struct y_ps90_rpe : gtl_yes {}; + + template <typename geometry_type_1, typename coordinate_type_1> + typename enable_if< typename gtl_and_3<y_ps90_rpe, + typename is_mutable_polygon_90_set_type<geometry_type_1>::type, + typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type>::type, + geometry_type_1>::type & + operator+=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { + return resize(lvalue, rvalue); + } + + struct y_ps90_rme : gtl_yes {}; + + template <typename geometry_type_1, typename coordinate_type_1> + typename enable_if< typename gtl_and_3<y_ps90_rme, + typename is_mutable_polygon_90_set_type<geometry_type_1>::type, + typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type>::type, + geometry_type_1>::type & + operator-=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { + return resize(lvalue, -rvalue); + } + + struct y_ps90_rp : gtl_yes {}; + + template <typename geometry_type_1, typename coordinate_type_1> + typename enable_if< typename gtl_and_3<y_ps90_rp, + typename gtl_if<typename is_mutable_polygon_90_set_type<geometry_type_1>::type>::type, + typename gtl_if<typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type>::type>::type, + geometry_type_1>::type + operator+(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { + geometry_type_1 retval(lvalue); + retval += rvalue; + return retval; + } + + struct y_ps90_rm : gtl_yes {}; + + template <typename geometry_type_1, typename coordinate_type_1> + typename enable_if< typename gtl_and_3<y_ps90_rm, + typename gtl_if<typename is_mutable_polygon_90_set_type<geometry_type_1>::type>::type, + typename gtl_if<typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type>::type>::type, + geometry_type_1>::type + operator-(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { + geometry_type_1 retval(lvalue); + retval -= rvalue; + return retval; + } + } +} +} +#endif + diff --git a/boost/polygon/detail/polygon_90_touch.hpp b/boost/polygon/detail/polygon_90_touch.hpp new file mode 100644 index 0000000000..7671602404 --- /dev/null +++ b/boost/polygon/detail/polygon_90_touch.hpp @@ -0,0 +1,418 @@ +/* + 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_POLYGON_90_TOUCH_HPP +#define BOOST_POLYGON_POLYGON_90_TOUCH_HPP +namespace boost { namespace polygon{ + + template <typename Unit> + struct touch_90_operation { + typedef interval_data<Unit> Interval; + + class TouchScanEvent { + private: + typedef std::map<Unit, std::set<int> > EventData; + EventData eventData_; + public: + + // The TouchScanEvent::iterator is a lazy algorithm that accumulates + // polygon ids in a set as it is incremented through the + // scan event data structure. + // The iterator provides a forward iterator semantic only. + class iterator { + private: + typename EventData::const_iterator itr_; + std::pair<Interval, std::set<int> > ivlIds_; + bool incremented_; + public: + inline iterator() : itr_(), ivlIds_(), incremented_(false) {} + inline iterator(typename EventData::const_iterator itr, + Unit prevPos, Unit curPos, const std::set<int>& ivlIds) : itr_(itr), ivlIds_(), incremented_(false) { + ivlIds_.second = ivlIds; + ivlIds_.first = Interval(prevPos, curPos); + } + inline iterator(const iterator& that) : itr_(), ivlIds_(), incremented_(false) { (*this) = that; } + inline iterator& operator=(const iterator& that) { + itr_ = that.itr_; + ivlIds_.first = that.ivlIds_.first; + ivlIds_.second = that.ivlIds_.second; + incremented_ = that.incremented_; + return *this; + } + inline bool operator==(const iterator& that) { return itr_ == that.itr_; } + inline bool operator!=(const iterator& that) { return itr_ != that.itr_; } + inline iterator& operator++() { + //std::cout << "increment\n"; + //std::cout << "state\n"; + //for(std::set<int>::iterator itr = ivlIds_.second.begin(); itr != ivlIds_.second.end(); ++itr) { + // std::cout << (*itr) << " "; + //} std::cout << std::endl; + //std::cout << "update\n"; + for(std::set<int>::const_iterator itr = (*itr_).second.begin(); + itr != (*itr_).second.end(); ++itr) { + //std::cout << (*itr) << " "; + std::set<int>::iterator lb = ivlIds_.second.find(*itr); + if(lb != ivlIds_.second.end()) { + ivlIds_.second.erase(lb); + } else { + ivlIds_.second.insert(*itr); + } + } + //std::cout << std::endl; + //std::cout << "new state\n"; + //for(std::set<int>::iterator itr = ivlIds_.second.begin(); itr != ivlIds_.second.end(); ++itr) { + // std::cout << (*itr) << " "; + //} std::cout << std::endl; + ++itr_; + //ivlIds_.first = Interval(ivlIds_.first.get(HIGH), itr_->first); + incremented_ = true; + return *this; + } + inline const iterator operator++(int){ + iterator tmpItr(*this); + ++(*this); + return tmpItr; + } + inline std::pair<Interval, std::set<int> >& operator*() { + if(incremented_) ivlIds_.first = Interval(ivlIds_.first.get(HIGH), itr_->first); + incremented_ = false; + if(ivlIds_.second.empty())(++(*this)); + if(incremented_) ivlIds_.first = Interval(ivlIds_.first.get(HIGH), itr_->first); + incremented_ = false; + return ivlIds_; } + }; + + inline TouchScanEvent() : eventData_() {} + template<class iT> + inline TouchScanEvent(iT begin, iT end) : eventData_() { + for( ; begin != end; ++begin){ + insert(*begin); + } + } + inline TouchScanEvent(const TouchScanEvent& that) : eventData_(that.eventData_) {} + inline TouchScanEvent& operator=(const TouchScanEvent& that){ + eventData_ = that.eventData_; + return *this; + } + + //Insert an interval polygon id into the EventData + inline void insert(const std::pair<Interval, int>& intervalId){ + insert(intervalId.first.low(), intervalId.second); + insert(intervalId.first.high(), intervalId.second); + } + + //Insert an position and polygon id into EventData + inline void insert(Unit pos, int id) { + typename EventData::iterator lb = eventData_.lower_bound(pos); + if(lb != eventData_.end() && lb->first == pos) { + std::set<int>& mr (lb->second); + std::set<int>::iterator mri = mr.find(id); + if(mri == mr.end()) { + mr.insert(id); + } else { + mr.erase(id); + } + } else { + lb = eventData_.insert(lb, std::pair<Unit, std::set<int> >(pos, std::set<int>())); + (*lb).second.insert(id); + } + } + + //merge this scan event with that by inserting its data + inline void insert(const TouchScanEvent& that){ + typename EventData::const_iterator itr; + for(itr = that.eventData_.begin(); itr != that.eventData_.end(); ++itr) { + eventData_[(*itr).first].insert(itr->second.begin(), itr->second.end()); + } + } + + //Get the begin iterator over event data + inline iterator begin() const { + //std::cout << "begin\n"; + if(eventData_.empty()) return end(); + typename EventData::const_iterator itr = eventData_.begin(); + Unit pos = itr->first; + const std::set<int>& idr = itr->second; + ++itr; + return iterator(itr, pos, itr->first, idr); + } + + //Get the end iterator over event data + inline iterator end() const { return iterator(eventData_.end(), 0, 0, std::set<int>()); } + + inline void clear() { eventData_.clear(); } + + inline Interval extents() const { + if(eventData_.empty()) return Interval(); + return Interval((*(eventData_.begin())).first, (*(eventData_.rbegin())).first); + } + }; + + //declaration of a map of scan events by coordinate value used to store all the + //polygon data for a single layer input into the scanline algorithm + typedef std::pair<std::map<Unit, TouchScanEvent>, std::map<Unit, TouchScanEvent> > TouchSetData; + + class TouchOp { + public: + typedef std::map<Unit, std::set<int> > ScanData; + typedef std::pair<Unit, std::set<int> > ElementType; + protected: + ScanData scanData_; + typename ScanData::iterator nextItr_; + public: + inline TouchOp () : scanData_(), nextItr_() { nextItr_ = scanData_.end(); } + inline TouchOp (const TouchOp& that) : scanData_(that.scanData_), nextItr_() { nextItr_ = scanData_.begin(); } + inline TouchOp& operator=(const TouchOp& that); + + //moves scanline forward + inline void advanceScan() { nextItr_ = scanData_.begin(); } + + //proceses the given interval and std::set<int> data + //the output data structre is a graph, the indicies in the vector correspond to graph nodes, + //the integers in the set are vector indicies and are the nodes with which that node shares an edge + template <typename graphT> + inline void processInterval(graphT& outputContainer, Interval ivl, const std::set<int>& ids, bool leadingEdge) { + //print(); + typename ScanData::iterator lowItr = lookup_(ivl.low()); + typename ScanData::iterator highItr = lookup_(ivl.high()); + //std::cout << "Interval: " << ivl << std::endl; + //for(std::set<int>::const_iterator itr = ids.begin(); itr != ids.end(); ++itr) + // std::cout << (*itr) << " "; + //std::cout << std::endl; + //add interval to scan data if it is past the end + if(lowItr == scanData_.end()) { + //std::cout << "case0" << std::endl; + lowItr = insert_(ivl.low(), ids); + evaluateBorder_(outputContainer, ids, ids); + highItr = insert_(ivl.high(), std::set<int>()); + return; + } + //ensure that highItr points to the end of the ivl + if(highItr == scanData_.end() || (*highItr).first > ivl.high()) { + //std::cout << "case1" << std::endl; + //std::cout << highItr->first << std::endl; + std::set<int> value = std::set<int>(); + if(highItr != scanData_.begin()) { + --highItr; + //std::cout << highItr->first << std::endl; + //std::cout << "high set size " << highItr->second.size() << std::endl; + value = highItr->second; + } + nextItr_ = highItr; + highItr = insert_(ivl.high(), value); + } else { + //evaluate border with next higher interval + //std::cout << "case1a" << std::endl; + if(leadingEdge)evaluateBorder_(outputContainer, highItr->second, ids); + } + //split the low interval if needed + if(lowItr->first > ivl.low()) { + //std::cout << "case2" << std::endl; + if(lowItr != scanData_.begin()) { + //std::cout << "case3" << std::endl; + --lowItr; + nextItr_ = lowItr; + //std::cout << lowItr->first << " " << lowItr->second.size() << std::endl; + lowItr = insert_(ivl.low(), lowItr->second); + } else { + //std::cout << "case4" << std::endl; + nextItr_ = lowItr; + lowItr = insert_(ivl.low(), std::set<int>()); + } + } else { + //evaluate border with next higher interval + //std::cout << "case2a" << std::endl; + typename ScanData::iterator nextLowerItr = lowItr; + if(leadingEdge && nextLowerItr != scanData_.begin()){ + --nextLowerItr; + evaluateBorder_(outputContainer, nextLowerItr->second, ids); + } + } + //std::cout << "low: " << lowItr->first << " high: " << highItr->first << std::endl; + //print(); + //process scan data intersecting interval + for(typename ScanData::iterator itr = lowItr; itr != highItr; ){ + //std::cout << "case5" << std::endl; + //std::cout << itr->first << std::endl; + std::set<int>& beforeIds = itr->second; + ++itr; + evaluateInterval_(outputContainer, beforeIds, ids, leadingEdge); + } + //print(); + //merge the bottom interval with the one below if they have the same count + if(lowItr != scanData_.begin()){ + //std::cout << "case6" << std::endl; + typename ScanData::iterator belowLowItr = lowItr; + --belowLowItr; + if(belowLowItr->second == lowItr->second) { + //std::cout << "case7" << std::endl; + scanData_.erase(lowItr); + } + } + //merge the top interval with the one above if they have the same count + if(highItr != scanData_.begin()) { + //std::cout << "case8" << std::endl; + typename ScanData::iterator beforeHighItr = highItr; + --beforeHighItr; + if(beforeHighItr->second == highItr->second) { + //std::cout << "case9" << std::endl; + scanData_.erase(highItr); + highItr = beforeHighItr; + ++highItr; + } + } + //print(); + nextItr_ = highItr; + } + +// inline void print() const { +// for(typename ScanData::const_iterator itr = scanData_.begin(); itr != scanData_.end(); ++itr) { +// std::cout << itr->first << ": "; +// for(std::set<int>::const_iterator sitr = itr->second.begin(); +// sitr != itr->second.end(); ++sitr){ +// std::cout << *sitr << " "; +// } +// std::cout << std::endl; +// } +// } + + 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, const std::set<int>& ids){ + //std::cout << "inserting " << ids.size() << " ids at: " << pos << std::endl; + return nextItr_ = scanData_.insert(nextItr_, std::pair<Unit, std::set<int> >(pos, ids)); + } + + template <typename graphT> + inline void evaluateInterval_(graphT& outputContainer, std::set<int>& ids, + const std::set<int>& changingIds, bool leadingEdge) { + for(std::set<int>::const_iterator ciditr = changingIds.begin(); ciditr != changingIds.end(); ++ciditr){ + //std::cout << "evaluateInterval " << (*ciditr) << std::endl; + evaluateId_(outputContainer, ids, *ciditr, leadingEdge); + } + } + template <typename graphT> + inline void evaluateBorder_(graphT& outputContainer, const std::set<int>& ids, const std::set<int>& changingIds) { + for(std::set<int>::const_iterator ciditr = changingIds.begin(); ciditr != changingIds.end(); ++ciditr){ + //std::cout << "evaluateBorder " << (*ciditr) << std::endl; + evaluateBorderId_(outputContainer, ids, *ciditr); + } + } + template <typename graphT> + inline void evaluateBorderId_(graphT& outputContainer, const std::set<int>& ids, int changingId) { + for(std::set<int>::const_iterator scanItr = ids.begin(); scanItr != ids.end(); ++scanItr) { + //std::cout << "create edge: " << changingId << " " << *scanItr << std::endl; + if(changingId != *scanItr){ + outputContainer[changingId].insert(*scanItr); + outputContainer[*scanItr].insert(changingId); + } + } + } + template <typename graphT> + inline void evaluateId_(graphT& outputContainer, std::set<int>& ids, int changingId, bool leadingEdge) { + //std::cout << "changingId: " << changingId << std::endl; + //for( std::set<int>::iterator itr = ids.begin(); itr != ids.end(); ++itr){ + // std::cout << *itr << " "; + //}std::cout << std::endl; + std::set<int>::iterator lb = ids.lower_bound(changingId); + if(lb == ids.end() || (*lb) != changingId) { + if(leadingEdge) { + //std::cout << "insert\n"; + //insert and add to output + for(std::set<int>::iterator scanItr = ids.begin(); scanItr != ids.end(); ++scanItr) { + //std::cout << "create edge: " << changingId << " " << *scanItr << std::endl; + if(changingId != *scanItr){ + outputContainer[changingId].insert(*scanItr); + outputContainer[*scanItr].insert(changingId); + } + } + ids.insert(changingId); + } + } else { + if(!leadingEdge){ + //std::cout << "erase\n"; + ids.erase(lb); + } + } + } + }; + + template <typename graphT> + static inline void processEvent(graphT& outputContainer, TouchOp& op, const TouchScanEvent& data, bool leadingEdge) { + for(typename TouchScanEvent::iterator itr = data.begin(); itr != data.end(); ++itr) { + //std::cout << "processInterval" << std::endl; + op.processInterval(outputContainer, (*itr).first, (*itr).second, leadingEdge); + } + } + + template <typename graphT> + static inline void performTouch(graphT& outputContainer, const TouchSetData& data) { + typename std::map<Unit, TouchScanEvent>::const_iterator leftItr = data.first.begin(); + typename std::map<Unit, TouchScanEvent>::const_iterator rightItr = data.second.begin(); + typename std::map<Unit, TouchScanEvent>::const_iterator leftEnd = data.first.end(); + typename std::map<Unit, TouchScanEvent>::const_iterator rightEnd = data.second.end(); + TouchOp op; + while(leftItr != leftEnd || rightItr != rightEnd) { + //std::cout << "loop" << std::endl; + op.advanceScan(); + //rightItr cannont be at end if leftItr is not at end + if(leftItr != leftEnd && rightItr != rightEnd && + leftItr->first <= rightItr->first) { + //std::cout << "case1" << std::endl; + //std::cout << leftItr ->first << std::endl; + processEvent(outputContainer, op, leftItr->second, true); + ++leftItr; + } else { + //std::cout << "case2" << std::endl; + //std::cout << rightItr ->first << std::endl; + processEvent(outputContainer, op, rightItr->second, false); + ++rightItr; + } + } + } + + template <class iT> + static inline void populateTouchSetData(TouchSetData& data, iT beginData, iT endData, int id) { + Unit prevPos = ((std::numeric_limits<Unit>::max)()); + Unit prevY = prevPos; + int count = 0; + for(iT itr = beginData; itr != endData; ++itr) { + Unit pos = (*itr).first; + if(pos != prevPos) { + prevPos = pos; + prevY = (*itr).second.first; + count = (*itr).second.second; + continue; + } + Unit y = (*itr).second.first; + if(count != 0 && y != prevY) { + std::pair<Interval, int> element(Interval(prevY, y), id); + if(count > 0) { + data.first[pos].insert(element); + } else { + data.second[pos].insert(element); + } + } + prevY = y; + count += (*itr).second.second; + } + } + + static inline void populateTouchSetData(TouchSetData& data, const std::vector<std::pair<Unit, std::pair<Unit, int> > >& inputData, int id) { + populateTouchSetData(data, inputData.begin(), inputData.end(), id); + } + + }; +} +} +#endif diff --git a/boost/polygon/detail/polygon_arbitrary_formation.hpp b/boost/polygon/detail/polygon_arbitrary_formation.hpp new file mode 100644 index 0000000000..5adabb8078 --- /dev/null +++ b/boost/polygon/detail/polygon_arbitrary_formation.hpp @@ -0,0 +1,2932 @@ +/* + 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_POLYGON_ARBITRARY_FORMATION_HPP +#define BOOST_POLYGON_POLYGON_ARBITRARY_FORMATION_HPP +namespace boost { namespace polygon{ + template <typename T, typename T2> + struct PolyLineArbitraryByConcept {}; + + template <typename T> + class poly_line_arbitrary_polygon_data; + template <typename T> + class poly_line_arbitrary_hole_data; + + template <typename Unit> + struct scanline_base { + + typedef point_data<Unit> Point; + typedef std::pair<Point, Point> half_edge; + + class less_point : public std::binary_function<Point, Point, bool> { + public: + inline less_point() {} + inline bool operator () (const Point& pt1, const Point& pt2) const { + if(pt1.get(HORIZONTAL) < pt2.get(HORIZONTAL)) return true; + if(pt1.get(HORIZONTAL) == pt2.get(HORIZONTAL)) { + if(pt1.get(VERTICAL) < pt2.get(VERTICAL)) return true; + } + return false; + } + }; + + static inline bool between(Point pt, Point pt1, Point pt2) { + less_point lp; + if(lp(pt1, pt2)) + return lp(pt, pt2) && lp(pt1, pt); + return lp(pt, pt1) && lp(pt2, pt); + } + + template <typename area_type> + static inline Unit compute_intercept(const area_type& dy2, + const area_type& dx1, + const area_type& dx2) { + //intercept = dy2 * dx1 / dx2 + //return (Unit)(((area_type)dy2 * (area_type)dx1) / (area_type)dx2); + area_type dx1_q = dx1 / dx2; + area_type dx1_r = dx1 % dx2; + return dx1_q * dy2 + (dy2 * dx1_r)/dx2; + } + + template <typename area_type> + static inline bool equal_slope(area_type dx1, area_type dy1, area_type dx2, area_type dy2) { + typedef typename coordinate_traits<Unit>::unsigned_area_type unsigned_product_type; + unsigned_product_type cross_1 = (unsigned_product_type)(dx2 < 0 ? -dx2 :dx2) * (unsigned_product_type)(dy1 < 0 ? -dy1 : dy1); + unsigned_product_type cross_2 = (unsigned_product_type)(dx1 < 0 ? -dx1 :dx1) * (unsigned_product_type)(dy2 < 0 ? -dy2 : dy2); + int dx1_sign = dx1 < 0 ? -1 : 1; + int dx2_sign = dx2 < 0 ? -1 : 1; + int dy1_sign = dy1 < 0 ? -1 : 1; + int dy2_sign = dy2 < 0 ? -1 : 1; + int cross_1_sign = dx2_sign * dy1_sign; + int cross_2_sign = dx1_sign * dy2_sign; + return cross_1 == cross_2 && (cross_1_sign == cross_2_sign || cross_1 == 0); + } + + template <typename T> + static inline bool equal_slope_hp(const T& dx1, const T& dy1, const T& dx2, const T& dy2) { + return dx1 * dy2 == dx2 * dy1; + } + + static inline bool equal_slope(const Unit& x, const Unit& y, + const Point& pt1, const Point& pt2) { + const Point* pts[2] = {&pt1, &pt2}; + typedef typename coordinate_traits<Unit>::manhattan_area_type at; + at dy2 = (at)pts[1]->get(VERTICAL) - (at)y; + at dy1 = (at)pts[0]->get(VERTICAL) - (at)y; + at dx2 = (at)pts[1]->get(HORIZONTAL) - (at)x; + at dx1 = (at)pts[0]->get(HORIZONTAL) - (at)x; + return equal_slope(dx1, dy1, dx2, dy2); + } + + template <typename area_type> + static inline bool less_slope(area_type dx1, area_type dy1, area_type dx2, area_type dy2) { + //reflext x and y slopes to right hand side half plane + if(dx1 < 0) { + dy1 *= -1; + dx1 *= -1; + } else if(dx1 == 0) { + //if the first slope is vertical the first cannot be less + return false; + } + if(dx2 < 0) { + dy2 *= -1; + dx2 *= -1; + } else if(dx2 == 0) { + //if the second slope is vertical the first is always less unless it is also vertical, in which case they are equal + return dx1 != 0; + } + typedef typename coordinate_traits<Unit>::unsigned_area_type unsigned_product_type; + unsigned_product_type cross_1 = (unsigned_product_type)(dx2 < 0 ? -dx2 :dx2) * (unsigned_product_type)(dy1 < 0 ? -dy1 : dy1); + unsigned_product_type cross_2 = (unsigned_product_type)(dx1 < 0 ? -dx1 :dx1) * (unsigned_product_type)(dy2 < 0 ? -dy2 : dy2); + int dx1_sign = dx1 < 0 ? -1 : 1; + int dx2_sign = dx2 < 0 ? -1 : 1; + int dy1_sign = dy1 < 0 ? -1 : 1; + int dy2_sign = dy2 < 0 ? -1 : 1; + int cross_1_sign = dx2_sign * dy1_sign; + int cross_2_sign = dx1_sign * dy2_sign; + if(cross_1_sign < cross_2_sign) return true; + if(cross_2_sign < cross_1_sign) return false; + if(cross_1_sign == -1) return cross_2 < cross_1; + return cross_1 < cross_2; + } + + static inline bool less_slope(const Unit& x, const Unit& y, + const Point& pt1, const Point& pt2) { + const Point* pts[2] = {&pt1, &pt2}; + //compute y value on edge from pt_ to pts[1] at the x value of pts[0] + typedef typename coordinate_traits<Unit>::manhattan_area_type at; + at dy2 = (at)pts[1]->get(VERTICAL) - (at)y; + at dy1 = (at)pts[0]->get(VERTICAL) - (at)y; + at dx2 = (at)pts[1]->get(HORIZONTAL) - (at)x; + at dx1 = (at)pts[0]->get(HORIZONTAL) - (at)x; + return less_slope(dx1, dy1, dx2, dy2); + } + + //return -1 below, 0 on and 1 above line + static inline int on_above_or_below(Point pt, const half_edge& he) { + if(pt == he.first || pt == he.second) return 0; + if(equal_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), he.first, he.second)) return 0; + bool less_result = less_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), he.first, he.second); + int retval = less_result ? -1 : 1; + less_point lp; + if(lp(he.second, he.first)) retval *= -1; + if(!between(pt, he.first, he.second)) retval *= -1; + return retval; + } + + //returns true is the segment intersects the integer grid square with lower + //left corner at point + static inline bool intersects_grid(Point pt, const half_edge& he) { + if(pt == he.second) return true; + if(pt == he.first) return true; + rectangle_data<Unit> rect1; + set_points(rect1, he.first, he.second); + if(contains(rect1, pt, true)) { + if(is_vertical(he) || is_horizontal(he)) return true; + } else { + return false; //can't intersect a grid not within bounding box + } + Unit x = pt.get(HORIZONTAL); + Unit y = pt.get(VERTICAL); + if(equal_slope(x, y, he.first, he.second) && + between(pt, he.first, he.second)) return true; + Point pt01(pt.get(HORIZONTAL), pt.get(VERTICAL) + 1); + Point pt10(pt.get(HORIZONTAL) + 1, pt.get(VERTICAL)); + Point pt11(pt.get(HORIZONTAL) + 1, pt.get(VERTICAL) + 1); +// if(pt01 == he.first) return true; +// if(pt10 == he.first) return true; +// if(pt11 == he.first) return true; +// if(pt01 == he.second) return true; +// if(pt10 == he.second) return true; +// if(pt11 == he.second) return true; + //check non-integer intersections + half_edge widget1(pt, pt11); + //intersects but not just at pt11 + if(intersects(widget1, he) && on_above_or_below(pt11, he)) return true; + half_edge widget2(pt01, pt10); + //intersects but not just at pt01 or 10 + if(intersects(widget2, he) && on_above_or_below(pt01, he) && on_above_or_below(pt10, he)) return true; + return false; + } + + static inline Unit evalAtXforYlazy(Unit xIn, Point pt, Point other_pt) { + long double + evalAtXforYret, evalAtXforYxIn, evalAtXforYx1, evalAtXforYy1, evalAtXforYdx1, evalAtXforYdx, + evalAtXforYdy, evalAtXforYx2, evalAtXforYy2, evalAtXforY0; + //y = (x - x1)dy/dx + y1 + //y = (xIn - pt.x)*(other_pt.y-pt.y)/(other_pt.x-pt.x) + pt.y + //assert pt.x != other_pt.x + if(pt.y() == other_pt.y()) + return pt.y(); + evalAtXforYxIn = xIn; + evalAtXforYx1 = pt.get(HORIZONTAL); + evalAtXforYy1 = pt.get(VERTICAL); + evalAtXforYdx1 = evalAtXforYxIn - evalAtXforYx1; + evalAtXforY0 = 0; + if(evalAtXforYdx1 == evalAtXforY0) return (Unit)evalAtXforYy1; + evalAtXforYx2 = other_pt.get(HORIZONTAL); + evalAtXforYy2 = other_pt.get(VERTICAL); + + evalAtXforYdx = evalAtXforYx2 - evalAtXforYx1; + evalAtXforYdy = evalAtXforYy2 - evalAtXforYy1; + evalAtXforYret = ((evalAtXforYdx1) * evalAtXforYdy / evalAtXforYdx + evalAtXforYy1); + return (Unit)evalAtXforYret; + } + + static inline typename high_precision_type<Unit>::type evalAtXforY(Unit xIn, Point pt, Point other_pt) { + typename high_precision_type<Unit>::type + evalAtXforYret, evalAtXforYxIn, evalAtXforYx1, evalAtXforYy1, evalAtXforYdx1, evalAtXforYdx, + evalAtXforYdy, evalAtXforYx2, evalAtXforYy2, evalAtXforY0; + //y = (x - x1)dy/dx + y1 + //y = (xIn - pt.x)*(other_pt.y-pt.y)/(other_pt.x-pt.x) + pt.y + //assert pt.x != other_pt.x + typedef typename high_precision_type<Unit>::type high_precision; + if(pt.y() == other_pt.y()) + return (high_precision)pt.y(); + evalAtXforYxIn = (high_precision)xIn; + evalAtXforYx1 = pt.get(HORIZONTAL); + evalAtXforYy1 = pt.get(VERTICAL); + evalAtXforYdx1 = evalAtXforYxIn - evalAtXforYx1; + evalAtXforY0 = high_precision(0); + if(evalAtXforYdx1 == evalAtXforY0) return evalAtXforYret = evalAtXforYy1; + evalAtXforYx2 = (high_precision)other_pt.get(HORIZONTAL); + evalAtXforYy2 = (high_precision)other_pt.get(VERTICAL); + + evalAtXforYdx = evalAtXforYx2 - evalAtXforYx1; + evalAtXforYdy = evalAtXforYy2 - evalAtXforYy1; + evalAtXforYret = ((evalAtXforYdx1) * evalAtXforYdy / evalAtXforYdx + evalAtXforYy1); + return evalAtXforYret; + } + + struct evalAtXforYPack { + typename high_precision_type<Unit>::type + evalAtXforYret, evalAtXforYxIn, evalAtXforYx1, evalAtXforYy1, evalAtXforYdx1, evalAtXforYdx, + evalAtXforYdy, evalAtXforYx2, evalAtXforYy2, evalAtXforY0; + inline const typename high_precision_type<Unit>::type& evalAtXforY(Unit xIn, Point pt, Point other_pt) { + //y = (x - x1)dy/dx + y1 + //y = (xIn - pt.x)*(other_pt.y-pt.y)/(other_pt.x-pt.x) + pt.y + //assert pt.x != other_pt.x + typedef typename high_precision_type<Unit>::type high_precision; + if(pt.y() == other_pt.y()) { + evalAtXforYret = (high_precision)pt.y(); + return evalAtXforYret; + } + evalAtXforYxIn = (high_precision)xIn; + evalAtXforYx1 = pt.get(HORIZONTAL); + evalAtXforYy1 = pt.get(VERTICAL); + evalAtXforYdx1 = evalAtXforYxIn - evalAtXforYx1; + evalAtXforY0 = high_precision(0); + if(evalAtXforYdx1 == evalAtXforY0) return evalAtXforYret = evalAtXforYy1; + evalAtXforYx2 = (high_precision)other_pt.get(HORIZONTAL); + evalAtXforYy2 = (high_precision)other_pt.get(VERTICAL); + + evalAtXforYdx = evalAtXforYx2 - evalAtXforYx1; + evalAtXforYdy = evalAtXforYy2 - evalAtXforYy1; + evalAtXforYret = ((evalAtXforYdx1) * evalAtXforYdy / evalAtXforYdx + evalAtXforYy1); + return evalAtXforYret; + } + }; + + static inline bool is_vertical(const half_edge& he) { + return he.first.get(HORIZONTAL) == he.second.get(HORIZONTAL); + } + + static inline bool is_horizontal(const half_edge& he) { + return he.first.get(VERTICAL) == he.second.get(VERTICAL); + } + + static inline bool is_45_degree(const half_edge& he) { + return euclidean_distance(he.first, he.second, HORIZONTAL) == euclidean_distance(he.first, he.second, VERTICAL); + } + + //scanline comparator functor + class less_half_edge : public std::binary_function<half_edge, half_edge, bool> { + private: + Unit *x_; //x value at which to apply comparison + int *justBefore_; + evalAtXforYPack * pack_; + public: + inline less_half_edge() : x_(0), justBefore_(0), pack_(0) {} + inline less_half_edge(Unit *x, int *justBefore, evalAtXforYPack * packIn) : x_(x), justBefore_(justBefore), pack_(packIn) {} + inline less_half_edge(const less_half_edge& that) : x_(that.x_), justBefore_(that.justBefore_), + pack_(that.pack_){} + inline less_half_edge& operator=(const less_half_edge& that) { + x_ = that.x_; + justBefore_ = that.justBefore_; + pack_ = that.pack_; + return *this; } + inline bool operator () (const half_edge& elm1, const half_edge& elm2) const { + if((std::max)(elm1.first.y(), elm1.second.y()) < (std::min)(elm2.first.y(), elm2.second.y())) + return true; + if((std::min)(elm1.first.y(), elm1.second.y()) > (std::max)(elm2.first.y(), elm2.second.y())) + return false; + + //check if either x of elem1 is equal to x_ + Unit localx = *x_; + Unit elm1y = 0; + bool elm1_at_x = false; + if(localx == elm1.first.get(HORIZONTAL)) { + elm1_at_x = true; + elm1y = elm1.first.get(VERTICAL); + } else if(localx == elm1.second.get(HORIZONTAL)) { + elm1_at_x = true; + elm1y = elm1.second.get(VERTICAL); + } + Unit elm2y = 0; + bool elm2_at_x = false; + if(localx == elm2.first.get(HORIZONTAL)) { + elm2_at_x = true; + elm2y = elm2.first.get(VERTICAL); + } else if(localx == elm2.second.get(HORIZONTAL)) { + elm2_at_x = true; + elm2y = elm2.second.get(VERTICAL); + } + bool retval = false; + if(!(elm1_at_x && elm2_at_x)) { + //at least one of the segments doesn't have an end point a the current x + //-1 below, 1 above + int pt1_oab = on_above_or_below(elm1.first, half_edge(elm2.first, elm2.second)); + int pt2_oab = on_above_or_below(elm1.second, half_edge(elm2.first, elm2.second)); + if(pt1_oab == pt2_oab) { + if(pt1_oab == -1) + retval = true; //pt1 is below elm2 so elm1 is below elm2 + } else { + //the segments can't cross so elm2 is on whatever side of elm1 that one of its ends is + int pt3_oab = on_above_or_below(elm2.first, half_edge(elm1.first, elm1.second)); + if(pt3_oab == 1) + retval = true; //elm1's point is above elm1 + } + } else { + if(elm1y < elm2y) { + retval = true; + } else if(elm1y == elm2y) { + if(elm1 == elm2) + return false; + retval = less_slope(elm1.second.get(HORIZONTAL) - elm1.first.get(HORIZONTAL), + elm1.second.get(VERTICAL) - elm1.first.get(VERTICAL), + elm2.second.get(HORIZONTAL) - elm2.first.get(HORIZONTAL), + elm2.second.get(VERTICAL) - elm2.first.get(VERTICAL)); + retval = ((*justBefore_) != 0) ^ retval; + } + } + return retval; + } + }; + + template <typename unsigned_product_type> + static inline void unsigned_mod(unsigned_product_type& result, int& result_sign, unsigned_product_type a, int a_sign, unsigned_product_type b, int b_sign) { + result = a % b; + result_sign = a_sign; + } + + template <typename unsigned_product_type> + static inline void unsigned_add(unsigned_product_type& result, int& result_sign, unsigned_product_type a, int a_sign, unsigned_product_type b, int b_sign) { + int switcher = 0; + if(a_sign < 0) switcher += 1; + if(b_sign < 0) switcher += 2; + if(a < b) switcher += 4; + switch (switcher) { + case 0: //both positive + result = a + b; + result_sign = 1; + break; + case 1: //a is negative + result = a - b; + result_sign = -1; + break; + case 2: //b is negative + result = a - b; + result_sign = 1; + break; + case 3: //both negative + result = a + b; + result_sign = -1; + break; + case 4: //both positive + result = a + b; + result_sign = 1; + break; + case 5: //a is negative + result = b - a; + result_sign = 1; + break; + case 6: //b is negative + result = b - a; + result_sign = -1; + break; + case 7: //both negative + result = b + a; + result_sign = -1; + break; + }; + } + + struct compute_intersection_pack { + typedef typename high_precision_type<Unit>::type high_precision; + high_precision y_high, dx1, dy1, dx2, dy2, x11, x21, y11, y21, x_num, y_num, x_den, y_den, x, y; + static inline bool compute_lazy_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, + bool projected = false, bool round_closest = false) { + long double y_high, dx1, dy1, dx2, dy2, x11, x21, y11, y21, x_num, y_num, x_den, y_den, x, y; + typedef rectangle_data<Unit> Rectangle; + Rectangle rect1, rect2; + set_points(rect1, he1.first, he1.second); + set_points(rect2, he2.first, he2.second); + if(!projected && !::boost::polygon::intersects(rect1, rect2, true)) return false; + if(is_vertical(he1)) { + if(is_vertical(he2)) return false; + y_high = evalAtXforYlazy(he1.first.get(HORIZONTAL), he2.first, he2.second); + Unit y_local = (Unit)y_high; + if(y_high < y_local) --y_local; + if(projected || contains(rect1.get(VERTICAL), y_local, true)) { + intersection = Point(he1.first.get(HORIZONTAL), y_local); + return true; + } else { + return false; + } + } else if(is_vertical(he2)) { + y_high = evalAtXforYlazy(he2.first.get(HORIZONTAL), he1.first, he1.second); + Unit y_local = (Unit)y_high; + if(y_high < y_local) --y_local; + if(projected || contains(rect2.get(VERTICAL), y_local, true)) { + intersection = Point(he2.first.get(HORIZONTAL), y_local); + return true; + } else { + return false; + } + } + //the bounding boxes of the two line segments intersect, so we check closer to find the intersection point + dy2 = (he2.second.get(VERTICAL)) - + (he2.first.get(VERTICAL)); + dy1 = (he1.second.get(VERTICAL)) - + (he1.first.get(VERTICAL)); + dx2 = (he2.second.get(HORIZONTAL)) - + (he2.first.get(HORIZONTAL)); + dx1 = (he1.second.get(HORIZONTAL)) - + (he1.first.get(HORIZONTAL)); + if(equal_slope_hp(dx1, dy1, dx2, dy2)) return false; + //the line segments have different slopes + //we can assume that the line segments are not vertical because such an intersection is handled elsewhere + x11 = (he1.first.get(HORIZONTAL)); + x21 = (he2.first.get(HORIZONTAL)); + y11 = (he1.first.get(VERTICAL)); + y21 = (he2.first.get(VERTICAL)); + //Unit exp_x = ((at)x11 * (at)dy1 * (at)dx2 - (at)x21 * (at)dy2 * (at)dx1 + (at)y21 * (at)dx1 * (at)dx2 - (at)y11 * (at)dx1 * (at)dx2) / ((at)dy1 * (at)dx2 - (at)dy2 * (at)dx1); + //Unit exp_y = ((at)y11 * (at)dx1 * (at)dy2 - (at)y21 * (at)dx2 * (at)dy1 + (at)x21 * (at)dy1 * (at)dy2 - (at)x11 * (at)dy1 * (at)dy2) / ((at)dx1 * (at)dy2 - (at)dx2 * (at)dy1); + x_num = (x11 * dy1 * dx2 - x21 * dy2 * dx1 + y21 * dx1 * dx2 - y11 * dx1 * dx2); + x_den = (dy1 * dx2 - dy2 * dx1); + y_num = (y11 * dx1 * dy2 - y21 * dx2 * dy1 + x21 * dy1 * dy2 - x11 * dy1 * dy2); + y_den = (dx1 * dy2 - dx2 * dy1); + x = x_num / x_den; + y = y_num / y_den; + //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << std::endl; + //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << std::endl; + //Unit exp_x = compute_x_intercept<at>(x11, x21, y11, y21, dy1, dy2, dx1, dx2); + //Unit exp_y = compute_x_intercept<at>(y11, y21, x11, x21, dx1, dx2, dy1, dy2); + if(round_closest) { + x = x + 0.5; + y = y + 0.5; + } + Unit x_unit = (Unit)(x); + Unit y_unit = (Unit)(y); + //truncate downward if it went up due to negative number + if(x < x_unit) --x_unit; + if(y < y_unit) --y_unit; + if(is_horizontal(he1)) + y_unit = he1.first.y(); + if(is_horizontal(he2)) + y_unit = he2.first.y(); + //if(x != exp_x || y != exp_y) + // std::cout << exp_x << " " << exp_y << " " << x << " " << y << std::endl; + //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); + //Unit y2 = evalAtXforY(exp_x, he2.first, he2.second); + //std::cout << exp_x << " " << exp_y << " " << y1 << " " << y2 << std::endl; + Point result(x_unit, y_unit); + if(!projected && !contains(rect1, result, true)) return false; + if(!projected && !contains(rect2, result, true)) return false; + if(projected) { + rectangle_data<long double> inf_rect(-(long double)(std::numeric_limits<Unit>::max)(), + -(long double) (std::numeric_limits<Unit>::max)(), + (long double)(std::numeric_limits<Unit>::max)(), + (long double) (std::numeric_limits<Unit>::max)() ); + if(contains(inf_rect, point_data<long double>(x, y), true)) { + intersection = result; + return true; + } else + return false; + } + intersection = result; + return true; + } + + inline bool compute_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, + bool projected = false, bool round_closest = false) { + if(!projected && !intersects(he1, he2)) + return false; + bool lazy_success = compute_lazy_intersection(intersection, he1, he2, projected); + if(!projected) { + if(lazy_success) { + if(intersects_grid(intersection, he1) && + intersects_grid(intersection, he2)) + return true; + } + } else { + return lazy_success; + } + return compute_exact_intersection(intersection, he1, he2, projected, round_closest); + } + + inline bool compute_exact_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, + bool projected = false, bool round_closest = false) { + if(!projected && !intersects(he1, he2)) + return false; + typedef rectangle_data<Unit> Rectangle; + Rectangle rect1, rect2; + set_points(rect1, he1.first, he1.second); + set_points(rect2, he2.first, he2.second); + if(!::boost::polygon::intersects(rect1, rect2, true)) return false; + if(is_vertical(he1)) { + if(is_vertical(he2)) return false; + y_high = evalAtXforY(he1.first.get(HORIZONTAL), he2.first, he2.second); + Unit y = convert_high_precision_type<Unit>(y_high); + if(y_high < (high_precision)y) --y; + if(contains(rect1.get(VERTICAL), y, true)) { + intersection = Point(he1.first.get(HORIZONTAL), y); + return true; + } else { + return false; + } + } else if(is_vertical(he2)) { + y_high = evalAtXforY(he2.first.get(HORIZONTAL), he1.first, he1.second); + Unit y = convert_high_precision_type<Unit>(y_high); + if(y_high < (high_precision)y) --y; + if(contains(rect2.get(VERTICAL), y, true)) { + intersection = Point(he2.first.get(HORIZONTAL), y); + return true; + } else { + return false; + } + } + //the bounding boxes of the two line segments intersect, so we check closer to find the intersection point + dy2 = (high_precision)(he2.second.get(VERTICAL)) - + (high_precision)(he2.first.get(VERTICAL)); + dy1 = (high_precision)(he1.second.get(VERTICAL)) - + (high_precision)(he1.first.get(VERTICAL)); + dx2 = (high_precision)(he2.second.get(HORIZONTAL)) - + (high_precision)(he2.first.get(HORIZONTAL)); + dx1 = (high_precision)(he1.second.get(HORIZONTAL)) - + (high_precision)(he1.first.get(HORIZONTAL)); + if(equal_slope_hp(dx1, dy1, dx2, dy2)) return false; + //the line segments have different slopes + //we can assume that the line segments are not vertical because such an intersection is handled elsewhere + x11 = (high_precision)(he1.first.get(HORIZONTAL)); + x21 = (high_precision)(he2.first.get(HORIZONTAL)); + y11 = (high_precision)(he1.first.get(VERTICAL)); + y21 = (high_precision)(he2.first.get(VERTICAL)); + //Unit exp_x = ((at)x11 * (at)dy1 * (at)dx2 - (at)x21 * (at)dy2 * (at)dx1 + (at)y21 * (at)dx1 * (at)dx2 - (at)y11 * (at)dx1 * (at)dx2) / ((at)dy1 * (at)dx2 - (at)dy2 * (at)dx1); + //Unit exp_y = ((at)y11 * (at)dx1 * (at)dy2 - (at)y21 * (at)dx2 * (at)dy1 + (at)x21 * (at)dy1 * (at)dy2 - (at)x11 * (at)dy1 * (at)dy2) / ((at)dx1 * (at)dy2 - (at)dx2 * (at)dy1); + x_num = (x11 * dy1 * dx2 - x21 * dy2 * dx1 + y21 * dx1 * dx2 - y11 * dx1 * dx2); + x_den = (dy1 * dx2 - dy2 * dx1); + y_num = (y11 * dx1 * dy2 - y21 * dx2 * dy1 + x21 * dy1 * dy2 - x11 * dy1 * dy2); + y_den = (dx1 * dy2 - dx2 * dy1); + x = x_num / x_den; + y = y_num / y_den; + //std::cout << x << " " << y << std::endl; + //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << std::endl; + //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << std::endl; + //Unit exp_x = compute_x_intercept<at>(x11, x21, y11, y21, dy1, dy2, dx1, dx2); + //Unit exp_y = compute_x_intercept<at>(y11, y21, x11, x21, dx1, dx2, dy1, dy2); + if(round_closest) { + x = x + (high_precision)0.5; + y = y + (high_precision)0.5; + } + Unit x_unit = convert_high_precision_type<Unit>(x); + Unit y_unit = convert_high_precision_type<Unit>(y); + //truncate downward if it went up due to negative number + if(x < (high_precision)x_unit) --x_unit; + if(y < (high_precision)y_unit) --y_unit; + if(is_horizontal(he1)) + y_unit = he1.first.y(); + if(is_horizontal(he2)) + y_unit = he2.first.y(); + //if(x != exp_x || y != exp_y) + // std::cout << exp_x << " " << exp_y << " " << x << " " << y << std::endl; + //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); + //Unit y2 = evalAtXforY(exp_x, he2.first, he2.second); + //std::cout << exp_x << " " << exp_y << " " << y1 << " " << y2 << std::endl; + Point result(x_unit, y_unit); + if(!contains(rect1, result, true)) return false; + if(!contains(rect2, result, true)) return false; + if(projected) { + high_precision b1 = (high_precision) (std::numeric_limits<Unit>::min)(); + high_precision b2 = (high_precision) (std::numeric_limits<Unit>::max)(); + if(x > b2 || y > b2 || x < b1 || y < b1) + return false; + } + intersection = result; + return true; + } + }; + + static inline bool compute_intersection(Point& intersection, const half_edge& he1, const half_edge& he2) { + typedef typename high_precision_type<Unit>::type high_precision; + typedef rectangle_data<Unit> Rectangle; + Rectangle rect1, rect2; + set_points(rect1, he1.first, he1.second); + set_points(rect2, he2.first, he2.second); + if(!::boost::polygon::intersects(rect1, rect2, true)) return false; + if(is_vertical(he1)) { + if(is_vertical(he2)) return false; + high_precision y_high = evalAtXforY(he1.first.get(HORIZONTAL), he2.first, he2.second); + Unit y = convert_high_precision_type<Unit>(y_high); + if(y_high < (high_precision)y) --y; + if(contains(rect1.get(VERTICAL), y, true)) { + intersection = Point(he1.first.get(HORIZONTAL), y); + return true; + } else { + return false; + } + } else if(is_vertical(he2)) { + high_precision y_high = evalAtXforY(he2.first.get(HORIZONTAL), he1.first, he1.second); + Unit y = convert_high_precision_type<Unit>(y_high); + if(y_high < (high_precision)y) --y; + if(contains(rect2.get(VERTICAL), y, true)) { + intersection = Point(he2.first.get(HORIZONTAL), y); + return true; + } else { + return false; + } + } + //the bounding boxes of the two line segments intersect, so we check closer to find the intersection point + high_precision dy2 = (high_precision)(he2.second.get(VERTICAL)) - + (high_precision)(he2.first.get(VERTICAL)); + high_precision dy1 = (high_precision)(he1.second.get(VERTICAL)) - + (high_precision)(he1.first.get(VERTICAL)); + high_precision dx2 = (high_precision)(he2.second.get(HORIZONTAL)) - + (high_precision)(he2.first.get(HORIZONTAL)); + high_precision dx1 = (high_precision)(he1.second.get(HORIZONTAL)) - + (high_precision)(he1.first.get(HORIZONTAL)); + if(equal_slope_hp(dx1, dy1, dx2, dy2)) return false; + //the line segments have different slopes + //we can assume that the line segments are not vertical because such an intersection is handled elsewhere + high_precision x11 = (high_precision)(he1.first.get(HORIZONTAL)); + high_precision x21 = (high_precision)(he2.first.get(HORIZONTAL)); + high_precision y11 = (high_precision)(he1.first.get(VERTICAL)); + high_precision y21 = (high_precision)(he2.first.get(VERTICAL)); + //Unit exp_x = ((at)x11 * (at)dy1 * (at)dx2 - (at)x21 * (at)dy2 * (at)dx1 + (at)y21 * (at)dx1 * (at)dx2 - (at)y11 * (at)dx1 * (at)dx2) / ((at)dy1 * (at)dx2 - (at)dy2 * (at)dx1); + //Unit exp_y = ((at)y11 * (at)dx1 * (at)dy2 - (at)y21 * (at)dx2 * (at)dy1 + (at)x21 * (at)dy1 * (at)dy2 - (at)x11 * (at)dy1 * (at)dy2) / ((at)dx1 * (at)dy2 - (at)dx2 * (at)dy1); + high_precision x_num = (x11 * dy1 * dx2 - x21 * dy2 * dx1 + y21 * dx1 * dx2 - y11 * dx1 * dx2); + high_precision x_den = (dy1 * dx2 - dy2 * dx1); + high_precision y_num = (y11 * dx1 * dy2 - y21 * dx2 * dy1 + x21 * dy1 * dy2 - x11 * dy1 * dy2); + high_precision y_den = (dx1 * dy2 - dx2 * dy1); + high_precision x = x_num / x_den; + high_precision y = y_num / y_den; + //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << std::endl; + //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << std::endl; + //Unit exp_x = compute_x_intercept<at>(x11, x21, y11, y21, dy1, dy2, dx1, dx2); + //Unit exp_y = compute_x_intercept<at>(y11, y21, x11, x21, dx1, dx2, dy1, dy2); + Unit x_unit = convert_high_precision_type<Unit>(x); + Unit y_unit = convert_high_precision_type<Unit>(y); + //truncate downward if it went up due to negative number + if(x < (high_precision)x_unit) --x_unit; + if(y < (high_precision)y_unit) --y_unit; + if(is_horizontal(he1)) + y_unit = he1.first.y(); + if(is_horizontal(he2)) + y_unit = he2.first.y(); + //if(x != exp_x || y != exp_y) + // std::cout << exp_x << " " << exp_y << " " << x << " " << y << std::endl; + //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); + //Unit y2 = evalAtXforY(exp_x, he2.first, he2.second); + //std::cout << exp_x << " " << exp_y << " " << y1 << " " << y2 << std::endl; + Point result(x_unit, y_unit); + if(!contains(rect1, result, true)) return false; + if(!contains(rect2, result, true)) return false; + intersection = result; + return true; + } + + static inline bool intersects(const half_edge& he1, const half_edge& he2) { + typedef rectangle_data<Unit> Rectangle; + Rectangle rect1, rect2; + set_points(rect1, he1.first, he1.second); + set_points(rect2, he2.first, he2.second); + if(::boost::polygon::intersects(rect1, rect2, false)) { + if(he1.first == he2.first) { + if(he1.second != he2.second && equal_slope(he1.first.get(HORIZONTAL), he1.first.get(VERTICAL), + he1.second, he2.second)) { + return true; + } else { + return false; + } + } + if(he1.first == he2.second) { + if(he1.second != he2.first && equal_slope(he1.first.get(HORIZONTAL), he1.first.get(VERTICAL), + he1.second, he2.first)) { + return true; + } else { + return false; + } + } + if(he1.second == he2.first) { + if(he1.first != he2.second && equal_slope(he1.second.get(HORIZONTAL), he1.second.get(VERTICAL), + he1.first, he2.second)) { + return true; + } else { + return false; + } + } + if(he1.second == he2.second) { + if(he1.first != he2.first && equal_slope(he1.second.get(HORIZONTAL), he1.second.get(VERTICAL), + he1.first, he2.first)) { + return true; + } else { + return false; + } + } + int oab1 = on_above_or_below(he1.first, he2); + if(oab1 == 0 && between(he1.first, he2.first, he2.second)) return true; + int oab2 = on_above_or_below(he1.second, he2); + if(oab2 == 0 && between(he1.second, he2.first, he2.second)) return true; + if(oab1 == oab2 && oab1 != 0) return false; //both points of he1 are on same side of he2 + int oab3 = on_above_or_below(he2.first, he1); + if(oab3 == 0 && between(he2.first, he1.first, he1.second)) return true; + int oab4 = on_above_or_below(he2.second, he1); + if(oab4 == 0 && between(he2.second, he1.first, he1.second)) return true; + if(oab3 == oab4) return false; //both points of he2 are on same side of he1 + return true; //they must cross + } + if(is_vertical(he1) && is_vertical(he2) && he1.first.get(HORIZONTAL) == he2.first.get(HORIZONTAL)) + return ::boost::polygon::intersects(rect1.get(VERTICAL), rect2.get(VERTICAL), false) && + rect1.get(VERTICAL) != rect2.get(VERTICAL); + if(is_horizontal(he1) && is_horizontal(he2) && he1.first.get(VERTICAL) == he2.first.get(VERTICAL)) + return ::boost::polygon::intersects(rect1.get(HORIZONTAL), rect2.get(HORIZONTAL), false) && + rect1.get(HORIZONTAL) != rect2.get(HORIZONTAL); + return false; + } + + class vertex_half_edge { + public: + typedef typename high_precision_type<Unit>::type high_precision; + Point pt; + Point other_pt; // 1, 0 or -1 + int count; //dxdydTheta + inline vertex_half_edge() : pt(), other_pt(), count() {} + inline vertex_half_edge(const Point& point, const Point& other_point, int countIn) : pt(point), other_pt(other_point), count(countIn) {} + inline vertex_half_edge(const vertex_half_edge& vertex) : pt(vertex.pt), other_pt(vertex.other_pt), count(vertex.count) {} + inline vertex_half_edge& operator=(const vertex_half_edge& vertex){ + pt = vertex.pt; other_pt = vertex.other_pt; count = vertex.count; return *this; } + inline vertex_half_edge(const std::pair<Point, Point>& vertex) : pt(), other_pt(), count() {} + inline vertex_half_edge& operator=(const std::pair<Point, Point>& vertex){ return *this; } + inline bool operator==(const vertex_half_edge& vertex) const { + return pt == vertex.pt && other_pt == vertex.other_pt && count == vertex.count; } + inline bool operator!=(const vertex_half_edge& vertex) const { return !((*this) == vertex); } + inline bool operator==(const std::pair<Point, Point>& vertex) const { return false; } + inline bool operator!=(const std::pair<Point, Point>& vertex) const { return !((*this) == vertex); } + inline bool operator<(const vertex_half_edge& vertex) const { + if(pt.get(HORIZONTAL) < vertex.pt.get(HORIZONTAL)) return true; + if(pt.get(HORIZONTAL) == vertex.pt.get(HORIZONTAL)) { + if(pt.get(VERTICAL) < vertex.pt.get(VERTICAL)) return true; + if(pt.get(VERTICAL) == vertex.pt.get(VERTICAL)) { return less_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), + other_pt, vertex.other_pt); + } + } + return false; + } + inline bool operator>(const vertex_half_edge& vertex) const { return vertex < (*this); } + inline bool operator<=(const vertex_half_edge& vertex) const { return !((*this) > vertex); } + inline bool operator>=(const vertex_half_edge& vertex) const { return !((*this) < vertex); } + inline high_precision evalAtX(Unit xIn) const { return evalAtXforYlazy(xIn, pt, other_pt); } + inline bool is_vertical() const { + return pt.get(HORIZONTAL) == other_pt.get(HORIZONTAL); + } + inline bool is_begin() const { + return pt.get(HORIZONTAL) < other_pt.get(HORIZONTAL) || + (pt.get(HORIZONTAL) == other_pt.get(HORIZONTAL) && + (pt.get(VERTICAL) < other_pt.get(VERTICAL))); + } + }; + + //when scanning Vertex45 for polygon formation we need a scanline comparator functor + class less_vertex_half_edge : public std::binary_function<vertex_half_edge, vertex_half_edge, bool> { + private: + Unit *x_; //x value at which to apply comparison + int *justBefore_; + public: + inline less_vertex_half_edge() : x_(0), justBefore_(0) {} + inline less_vertex_half_edge(Unit *x, int *justBefore) : x_(x), justBefore_(justBefore) {} + inline less_vertex_half_edge(const less_vertex_half_edge& that) : x_(that.x_), justBefore_(that.justBefore_) {} + inline less_vertex_half_edge& operator=(const less_vertex_half_edge& that) { x_ = that.x_; justBefore_ = that.justBefore_; return *this; } + inline bool operator () (const vertex_half_edge& elm1, const vertex_half_edge& elm2) const { + if((std::max)(elm1.pt.y(), elm1.other_pt.y()) < (std::min)(elm2.pt.y(), elm2.other_pt.y())) + return true; + if((std::min)(elm1.pt.y(), elm1.other_pt.y()) > (std::max)(elm2.pt.y(), elm2.other_pt.y())) + return false; + //check if either x of elem1 is equal to x_ + Unit localx = *x_; + Unit elm1y = 0; + bool elm1_at_x = false; + if(localx == elm1.pt.get(HORIZONTAL)) { + elm1_at_x = true; + elm1y = elm1.pt.get(VERTICAL); + } else if(localx == elm1.other_pt.get(HORIZONTAL)) { + elm1_at_x = true; + elm1y = elm1.other_pt.get(VERTICAL); + } + Unit elm2y = 0; + bool elm2_at_x = false; + if(localx == elm2.pt.get(HORIZONTAL)) { + elm2_at_x = true; + elm2y = elm2.pt.get(VERTICAL); + } else if(localx == elm2.other_pt.get(HORIZONTAL)) { + elm2_at_x = true; + elm2y = elm2.other_pt.get(VERTICAL); + } + bool retval = false; + if(!(elm1_at_x && elm2_at_x)) { + //at least one of the segments doesn't have an end point a the current x + //-1 below, 1 above + int pt1_oab = on_above_or_below(elm1.pt, half_edge(elm2.pt, elm2.other_pt)); + int pt2_oab = on_above_or_below(elm1.other_pt, half_edge(elm2.pt, elm2.other_pt)); + if(pt1_oab == pt2_oab) { + if(pt1_oab == -1) + retval = true; //pt1 is below elm2 so elm1 is below elm2 + } else { + //the segments can't cross so elm2 is on whatever side of elm1 that one of its ends is + int pt3_oab = on_above_or_below(elm2.pt, half_edge(elm1.pt, elm1.other_pt)); + if(pt3_oab == 1) + retval = true; //elm1's point is above elm1 + } + } else { + if(elm1y < elm2y) { + retval = true; + } else if(elm1y == elm2y) { + if(elm1.pt == elm2.pt && elm1.other_pt == elm2.other_pt) + return false; + retval = less_slope(elm1.other_pt.get(HORIZONTAL) - elm1.pt.get(HORIZONTAL), + elm1.other_pt.get(VERTICAL) - elm1.pt.get(VERTICAL), + elm2.other_pt.get(HORIZONTAL) - elm2.pt.get(HORIZONTAL), + elm2.other_pt.get(VERTICAL) - elm2.pt.get(VERTICAL)); + retval = ((*justBefore_) != 0) ^ retval; + } + } + return retval; + } + }; + + }; + + template <typename Unit> + class polygon_arbitrary_formation : public scanline_base<Unit> { + public: + typedef typename scanline_base<Unit>::Point Point; + typedef typename scanline_base<Unit>::half_edge half_edge; + typedef typename scanline_base<Unit>::vertex_half_edge vertex_half_edge; + typedef typename scanline_base<Unit>::less_vertex_half_edge less_vertex_half_edge; + + class poly_line_arbitrary { + public: + typedef typename std::list<Point>::const_iterator iterator; + + // default constructor of point does not initialize x and y + inline poly_line_arbitrary() : points() {} //do nothing default constructor + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template<class iT> + inline poly_line_arbitrary& set(iT inputBegin, iT inputEnd) { + points.clear(); //just in case there was some old data there + while(inputBegin != inputEnd) { + points.insert(points.end(), *inputBegin); + ++inputBegin; + } + return *this; + } + + // copy constructor (since we have dynamic memory) + inline poly_line_arbitrary(const poly_line_arbitrary& that) : points(that.points) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline poly_line_arbitrary& operator=(const poly_line_arbitrary& that) { + points = that.points; + return *this; + } + + // get begin iterator, returns a pointer to a const Unit + inline iterator begin() const { return points.begin(); } + + // get end iterator, returns a pointer to a const Unit + inline iterator end() const { return points.end(); } + + inline std::size_t size() const { return points.size(); } + + //public data member + std::list<Point> points; + }; + + class active_tail_arbitrary { + protected: + //data + poly_line_arbitrary* tailp_; + active_tail_arbitrary *otherTailp_; + std::list<active_tail_arbitrary*> holesList_; + bool head_; + public: + + /** + * @brief iterator over coordinates of the figure + */ + typedef typename poly_line_arbitrary::iterator iterator; + + /** + * @brief iterator over holes contained within the figure + */ + typedef typename std::list<active_tail_arbitrary*>::const_iterator iteratorHoles; + + //default constructor + inline active_tail_arbitrary() : tailp_(), otherTailp_(), holesList_(), head_() {} + + //constructor + inline active_tail_arbitrary(const vertex_half_edge& vertex, active_tail_arbitrary* otherTailp = 0) : tailp_(), otherTailp_(), holesList_(), head_() { + tailp_ = new poly_line_arbitrary; + tailp_->points.push_back(vertex.pt); + //bool headArray[4] = {false, true, true, true}; + bool inverted = vertex.count == -1; + head_ = (!vertex.is_vertical) ^ inverted; + otherTailp_ = otherTailp; + } + + inline active_tail_arbitrary(Point point, active_tail_arbitrary* otherTailp, bool head = true) : + tailp_(), otherTailp_(), holesList_(), head_() { + tailp_ = new poly_line_arbitrary; + tailp_->points.push_back(point); + head_ = head; + otherTailp_ = otherTailp; + + } + inline active_tail_arbitrary(active_tail_arbitrary* otherTailp) : + tailp_(), otherTailp_(), holesList_(), head_() { + tailp_ = otherTailp->tailp_; + otherTailp_ = otherTailp; + } + + //copy constructor + inline active_tail_arbitrary(const active_tail_arbitrary& that) : + tailp_(), otherTailp_(), holesList_(), head_() { (*this) = that; } + + //destructor + inline ~active_tail_arbitrary() { + destroyContents(); + } + + //assignment operator + inline active_tail_arbitrary& operator=(const active_tail_arbitrary& that) { + tailp_ = new poly_line_arbitrary(*(that.tailp_)); + head_ = that.head_; + otherTailp_ = that.otherTailp_; + holesList_ = that.holesList_; + return *this; + } + + //equivalence operator + inline bool operator==(const active_tail_arbitrary& b) const { + return tailp_ == b.tailp_ && head_ == b.head_; + } + + /** + * @brief get the pointer to the polyline that this is an active tail of + */ + inline poly_line_arbitrary* getTail() const { return tailp_; } + + /** + * @brief get the pointer to the polyline at the other end of the chain + */ + inline poly_line_arbitrary* getOtherTail() const { return otherTailp_->tailp_; } + + /** + * @brief get the pointer to the activetail at the other end of the chain + */ + inline active_tail_arbitrary* getOtherActiveTail() const { return otherTailp_; } + + /** + * @brief test if another active tail is the other end of the chain + */ + inline bool isOtherTail(const active_tail_arbitrary& b) const { return &b == otherTailp_; } + + /** + * @brief update this end of chain pointer to new polyline + */ + inline active_tail_arbitrary& updateTail(poly_line_arbitrary* newTail) { tailp_ = newTail; return *this; } + + inline bool join(active_tail_arbitrary* tail) { + if(tail == otherTailp_) { + //std::cout << "joining to other tail!\n"; + return false; + } + if(tail->head_ == head_) { + //std::cout << "joining head to head!\n"; + return false; + } + if(!tailp_) { + //std::cout << "joining empty tail!\n"; + return false; + } + if(!(otherTailp_->head_)) { + otherTailp_->copyHoles(*tail); + otherTailp_->copyHoles(*this); + } else { + tail->otherTailp_->copyHoles(*this); + tail->otherTailp_->copyHoles(*tail); + } + poly_line_arbitrary* tail1 = tailp_; + poly_line_arbitrary* tail2 = tail->tailp_; + if(head_) std::swap(tail1, tail2); + typename std::list<point_data<Unit> >::reverse_iterator riter = tail1->points.rbegin(); + typename std::list<point_data<Unit> >::iterator iter = tail2->points.begin(); + if(*riter == *iter) { + tail1->points.pop_back(); //remove duplicate point + } + tail1->points.splice(tail1->points.end(), tail2->points); + delete tail2; + otherTailp_->tailp_ = tail1; + tail->otherTailp_->tailp_ = tail1; + otherTailp_->otherTailp_ = tail->otherTailp_; + tail->otherTailp_->otherTailp_ = otherTailp_; + tailp_ = 0; + tail->tailp_ = 0; + tail->otherTailp_ = 0; + otherTailp_ = 0; + return true; + } + + /** + * @brief associate a hole to this active tail by the specified policy + */ + inline active_tail_arbitrary* addHole(active_tail_arbitrary* hole) { + holesList_.push_back(hole); + copyHoles(*hole); + copyHoles(*(hole->otherTailp_)); + return this; + } + + /** + * @brief get the list of holes + */ + inline const std::list<active_tail_arbitrary*>& getHoles() const { return holesList_; } + + /** + * @brief copy holes from that to this + */ + inline void copyHoles(active_tail_arbitrary& that) { holesList_.splice(holesList_.end(), that.holesList_); } + + /** + * @brief find out if solid to right + */ + inline bool solidToRight() const { return !head_; } + inline bool solidToLeft() const { return head_; } + + /** + * @brief get vertex + */ + inline Point getPoint() const { + if(head_) return tailp_->points.front(); + return tailp_->points.back(); + } + + /** + * @brief add a coordinate to the polygon at this active tail end, properly handle degenerate edges by removing redundant coordinate + */ + inline void pushPoint(Point point) { + if(head_) { + //if(tailp_->points.size() < 2) { + // tailp_->points.push_front(point); + // return; + //} + typename std::list<Point>::iterator iter = tailp_->points.begin(); + if(iter == tailp_->points.end()) { + tailp_->points.push_front(point); + return; + } + ++iter; + if(iter == tailp_->points.end()) { + tailp_->points.push_front(point); + return; + } + --iter; + if(*iter != point) { + tailp_->points.push_front(point); + } + return; + } + //if(tailp_->points.size() < 2) { + // tailp_->points.push_back(point); + // return; + //} + typename std::list<Point>::reverse_iterator iter = tailp_->points.rbegin(); + if(iter == tailp_->points.rend()) { + tailp_->points.push_back(point); + return; + } + ++iter; + if(iter == tailp_->points.rend()) { + tailp_->points.push_back(point); + return; + } + --iter; + if(*iter != point) { + tailp_->points.push_back(point); + } + } + + /** + * @brief joins the two chains that the two active tail tails are ends of + * checks for closure of figure and writes out polygons appropriately + * returns a handle to a hole if one is closed + */ + template <class cT> + static inline active_tail_arbitrary* joinChains(Point point, active_tail_arbitrary* at1, active_tail_arbitrary* at2, bool solid, + cT& output) { + if(at1->otherTailp_ == at2) { + //if(at2->otherTailp_ != at1) std::cout << "half closed error\n"; + //we are closing a figure + at1->pushPoint(point); + at2->pushPoint(point); + if(solid) { + //we are closing a solid figure, write to output + //std::cout << "test1\n"; + at1->copyHoles(*(at1->otherTailp_)); + typename PolyLineArbitraryByConcept<Unit, typename geometry_concept<typename cT::value_type>::type>::type polyData(at1); + //poly_line_arbitrary_polygon_data polyData(at1); + //std::cout << "test2\n"; + //std::cout << poly << std::endl; + //std::cout << "test3\n"; + typedef typename cT::value_type result_type; + typedef typename geometry_concept<result_type>::type result_concept; + output.push_back(result_type()); + assign(output.back(), polyData); + //std::cout << "test4\n"; + //std::cout << "delete " << at1->otherTailp_ << std::endl; + //at1->print(); + //at1->otherTailp_->print(); + delete at1->otherTailp_; + //at1->print(); + //at1->otherTailp_->print(); + //std::cout << "test5\n"; + //std::cout << "delete " << at1 << std::endl; + delete at1; + //std::cout << "test6\n"; + return 0; + } else { + //we are closing a hole, return the tail end active tail of the figure + return at1; + } + } + //we are not closing a figure + at1->pushPoint(point); + at1->join(at2); + delete at1; + delete at2; + return 0; + } + + inline void destroyContents() { + if(otherTailp_) { + //std::cout << "delete p " << tailp_ << std::endl; + if(tailp_) delete tailp_; + tailp_ = 0; + otherTailp_->otherTailp_ = 0; + otherTailp_->tailp_ = 0; + otherTailp_ = 0; + } + for(typename std::list<active_tail_arbitrary*>::iterator itr = holesList_.begin(); itr != holesList_.end(); ++itr) { + //std::cout << "delete p " << (*itr) << std::endl; + if(*itr) { + if((*itr)->otherTailp_) { + delete (*itr)->otherTailp_; + (*itr)->otherTailp_ = 0; + } + delete (*itr); + } + (*itr) = 0; + } + holesList_.clear(); + } + + inline void print() { + //std::cout << this << " " << tailp_ << " " << otherTailp_ << " " << holesList_.size() << " " << head_ << std::endl; + } + + static inline std::pair<active_tail_arbitrary*, active_tail_arbitrary*> createActiveTailsAsPair(Point point, bool solid, + active_tail_arbitrary* phole, bool fractureHoles) { + active_tail_arbitrary* at1 = 0; + active_tail_arbitrary* at2 = 0; + if(phole && fractureHoles) { + //std::cout << "adding hole\n"; + at1 = phole; + //assert solid == false, we should be creating a corner with solid below and to the left if there was a hole + at2 = at1->getOtherActiveTail(); + at2->pushPoint(point); + at1->pushPoint(point); + } else { + at1 = new active_tail_arbitrary(point, at2, solid); + at2 = new active_tail_arbitrary(at1); + at1->otherTailp_ = at2; + at2->head_ = !solid; + if(phole) + at2->addHole(phole); //assert fractureHoles == false + } + return std::pair<active_tail_arbitrary*, active_tail_arbitrary*>(at1, at2); + } + + }; + + + typedef std::vector<std::pair<Point, int> > vertex_arbitrary_count; + + class less_half_edge_count : public std::binary_function<vertex_half_edge, vertex_half_edge, bool> { + private: + Point pt_; + public: + inline less_half_edge_count() : pt_() {} + inline less_half_edge_count(Point point) : pt_(point) {} + inline bool operator () (const std::pair<Point, int>& elm1, const std::pair<Point, int>& elm2) const { + return scanline_base<Unit>::less_slope(pt_.get(HORIZONTAL), pt_.get(VERTICAL), elm1.first, elm2.first); + } + }; + + static inline void sort_vertex_arbitrary_count(vertex_arbitrary_count& count, const Point& pt) { + less_half_edge_count lfec(pt); + gtlsort(count.begin(), count.end(), lfec); + } + + typedef std::vector<std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*> > incoming_count; + + class less_incoming_count : public std::binary_function<std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*>, + std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*>, bool> { + private: + Point pt_; + public: + inline less_incoming_count() : pt_() {} + inline less_incoming_count(Point point) : pt_(point) {} + inline bool operator () (const std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*>& elm1, + const std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*>& elm2) const { + Unit dx1 = elm1.first.first.first.get(HORIZONTAL) - elm1.first.first.second.get(HORIZONTAL); + Unit dx2 = elm2.first.first.first.get(HORIZONTAL) - elm2.first.first.second.get(HORIZONTAL); + Unit dy1 = elm1.first.first.first.get(VERTICAL) - elm1.first.first.second.get(VERTICAL); + Unit dy2 = elm2.first.first.first.get(VERTICAL) - elm2.first.first.second.get(VERTICAL); + return scanline_base<Unit>::less_slope(dx1, dy1, dx2, dy2); + } + }; + + static inline void sort_incoming_count(incoming_count& count, const Point& pt) { + less_incoming_count lfec(pt); + gtlsort(count.begin(), count.end(), lfec); + } + + static inline void compact_vertex_arbitrary_count(const Point& pt, vertex_arbitrary_count &count) { + if(count.empty()) return; + vertex_arbitrary_count tmp; + tmp.reserve(count.size()); + tmp.push_back(count[0]); + //merge duplicates + for(std::size_t i = 1; i < count.size(); ++i) { + if(!equal_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), tmp[i-1].first, count[i].first)) { + tmp.push_back(count[i]); + } else { + tmp.back().second += count[i].second; + } + } + count.clear(); + count.swap(tmp); + } + + // inline std::ostream& operator<< (std::ostream& o, const vertex_arbitrary_count& c) { +// for(unsinged int i = 0; i < c.size(); ++i) { +// o << c[i].first << " " << c[i].second << " "; +// } +// return o; +// } + + class vertex_arbitrary_compact { + public: + Point pt; + vertex_arbitrary_count count; + inline vertex_arbitrary_compact() : pt(), count() {} + inline vertex_arbitrary_compact(const Point& point, const Point& other_point, int countIn) : pt(point), count() { + count.push_back(std::pair<Point, int>(other_point, countIn)); + } + inline vertex_arbitrary_compact(const vertex_half_edge& vertex) : pt(vertex.pt), count() { + count.push_back(std::pair<Point, int>(vertex.other_pt, vertex.count)); + } + inline vertex_arbitrary_compact(const vertex_arbitrary_compact& vertex) : pt(vertex.pt), count(vertex.count) {} + inline vertex_arbitrary_compact& operator=(const vertex_arbitrary_compact& vertex){ + pt = vertex.pt; count = vertex.count; return *this; } + //inline vertex_arbitrary_compact(const std::pair<Point, Point>& vertex) {} + inline vertex_arbitrary_compact& operator=(const std::pair<Point, Point>& vertex){ return *this; } + inline bool operator==(const vertex_arbitrary_compact& vertex) const { + return pt == vertex.pt && count == vertex.count; } + inline bool operator!=(const vertex_arbitrary_compact& vertex) const { return !((*this) == vertex); } + inline bool operator==(const std::pair<Point, Point>& vertex) const { return false; } + inline bool operator!=(const std::pair<Point, Point>& vertex) const { return !((*this) == vertex); } + inline bool operator<(const vertex_arbitrary_compact& vertex) const { + if(pt.get(HORIZONTAL) < vertex.pt.get(HORIZONTAL)) return true; + if(pt.get(HORIZONTAL) == vertex.pt.get(HORIZONTAL)) { + return pt.get(VERTICAL) < vertex.pt.get(VERTICAL); + } + return false; + } + inline bool operator>(const vertex_arbitrary_compact& vertex) const { return vertex < (*this); } + inline bool operator<=(const vertex_arbitrary_compact& vertex) const { return !((*this) > vertex); } + inline bool operator>=(const vertex_arbitrary_compact& vertex) const { return !((*this) < vertex); } + inline bool have_vertex_half_edge(int index) const { return count[index]; } + inline vertex_half_edge operator[](int index) const { return vertex_half_edge(pt, count[index]); } + }; + +// inline std::ostream& operator<< (std::ostream& o, const vertex_arbitrary_compact& c) { +// o << c.pt << ", " << c.count; +// return o; +// } + + protected: + //definitions + typedef std::map<vertex_half_edge, active_tail_arbitrary*, less_vertex_half_edge> scanline_data; + typedef typename scanline_data::iterator iterator; + typedef typename scanline_data::const_iterator const_iterator; + + //data + scanline_data scanData_; + Unit x_; + int justBefore_; + int fractureHoles_; + public: + inline polygon_arbitrary_formation() : + scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false), fractureHoles_(0) { + less_vertex_half_edge lessElm(&x_, &justBefore_); + scanData_ = scanline_data(lessElm); + } + inline polygon_arbitrary_formation(bool fractureHoles) : + scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false), fractureHoles_(fractureHoles) { + less_vertex_half_edge lessElm(&x_, &justBefore_); + scanData_ = scanline_data(lessElm); + } + inline polygon_arbitrary_formation(const polygon_arbitrary_formation& that) : + scanData_(), x_((std::numeric_limits<Unit>::min)()), justBefore_(false), fractureHoles_(0) { (*this) = that; } + inline polygon_arbitrary_formation& operator=(const polygon_arbitrary_formation& that) { + x_ = that.x_; + justBefore_ = that.justBefore_; + fractureHoles_ = that.fractureHoles_; + less_vertex_half_edge lessElm(&x_, &justBefore_); + scanData_ = scanline_data(lessElm); + for(const_iterator itr = that.scanData_.begin(); itr != that.scanData_.end(); ++itr){ + scanData_.insert(scanData_.end(), *itr); + } + return *this; + } + + //cT is an output container of Polygon45 or Polygon45WithHoles + //iT is an iterator over vertex_half_edge elements + //inputBegin - inputEnd is a range of sorted iT that represents + //one or more scanline stops worth of data + template <class cT, class iT> + void scan(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "1\n"; + while(inputBegin != inputEnd) { + //std::cout << "2\n"; + x_ = (*inputBegin).pt.get(HORIZONTAL); + //std::cout << "SCAN FORMATION " << x_ << std::endl; + //std::cout << "x_ = " << x_ << std::endl; + //std::cout << "scan line size: " << scanData_.size() << std::endl; + inputBegin = processEvent_(output, inputBegin, inputEnd); + } + //std::cout << "scan line size: " << scanData_.size() << std::endl; + } + + protected: + //functions + template <class cT, class cT2> + inline std::pair<std::pair<Point, int>, active_tail_arbitrary*> processPoint_(cT& output, cT2& elements, Point point, + incoming_count& counts_from_scanline, vertex_arbitrary_count& incoming_count) { + //std::cout << "\nAT POINT: " << point << std::endl; + //join any closing solid corners + std::vector<int> counts; + std::vector<int> incoming; + std::vector<active_tail_arbitrary*> tails; + counts.reserve(counts_from_scanline.size()); + tails.reserve(counts_from_scanline.size()); + incoming.reserve(incoming_count.size()); + for(std::size_t i = 0; i < counts_from_scanline.size(); ++i) { + counts.push_back(counts_from_scanline[i].first.second); + tails.push_back(counts_from_scanline[i].second); + } + for(std::size_t i = 0; i < incoming_count.size(); ++i) { + incoming.push_back(incoming_count[i].second); + if(incoming_count[i].first < point) { + incoming.back() = 0; + } + } + + active_tail_arbitrary* returnValue = 0; + std::pair<Point, int> returnCount(Point(0, 0), 0); + int i_size_less_1 = (int)(incoming.size()) -1; + int c_size_less_1 = (int)(counts.size()) -1; + int i_size = incoming.size(); + int c_size = counts.size(); + + bool have_vertical_tail_from_below = false; + if(c_size && + scanline_base<Unit>::is_vertical(counts_from_scanline.back().first.first)) { + have_vertical_tail_from_below = true; + } + //assert size = size_less_1 + 1 + //std::cout << tails.size() << " " << incoming.size() << " " << counts_from_scanline.size() << " " << incoming_count.size() << std::endl; + // for(std::size_t i = 0; i < counts.size(); ++i) { + // std::cout << counts_from_scanline[i].first.first.first.get(HORIZONTAL) << ","; + // std::cout << counts_from_scanline[i].first.first.first.get(VERTICAL) << " "; + // std::cout << counts_from_scanline[i].first.first.second.get(HORIZONTAL) << ","; + // std::cout << counts_from_scanline[i].first.first.second.get(VERTICAL) << ":"; + // std::cout << counts_from_scanline[i].first.second << " "; + // } std::cout << std::endl; + // print(incoming_count); + { + for(int i = 0; i < c_size_less_1; ++i) { + //std::cout << i << std::endl; + if(counts[i] == -1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < c_size; ++j) { + //std::cout << j << std::endl; + if(counts[j]) { + if(counts[j] == 1) { + //std::cout << "case1: " << i << " " << j << std::endl; + //if a figure is closed it will be written out by this function to output + active_tail_arbitrary::joinChains(point, tails[i], tails[j], true, output); + counts[i] = 0; + counts[j] = 0; + tails[i] = 0; + tails[j] = 0; + } + break; + } + } + } + } + } + //find any pairs of incoming edges that need to create pair for leading solid + //std::cout << "checking case2\n"; + { + for(int i = 0; i < i_size_less_1; ++i) { + //std::cout << i << std::endl; + if(incoming[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < i_size; ++j) { + //std::cout << j << std::endl; + if(incoming[j]) { + //std::cout << incoming[j] << std::endl; + if(incoming[j] == -1) { + //std::cout << "case2: " << i << " " << j << std::endl; + //std::cout << "creating active tail pair\n"; + std::pair<active_tail_arbitrary*, active_tail_arbitrary*> tailPair = + active_tail_arbitrary::createActiveTailsAsPair(point, true, 0, fractureHoles_ != 0); + //tailPair.first->print(); + //tailPair.second->print(); + if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + //vertical active tail becomes return value + returnValue = tailPair.first; + returnCount.first = point; + returnCount.second = 1; + } else { + //std::cout << "new element " << j-1 << " " << -1 << std::endl; + //std::cout << point << " " << incoming_count[j].first << std::endl; + elements.push_back(std::pair<vertex_half_edge, + active_tail_arbitrary*>(vertex_half_edge(point, + incoming_count[j].first, -1), tailPair.first)); + } + //std::cout << "new element " << i-1 << " " << 1 << std::endl; + //std::cout << point << " " << incoming_count[i].first << std::endl; + elements.push_back(std::pair<vertex_half_edge, + active_tail_arbitrary*>(vertex_half_edge(point, + incoming_count[i].first, 1), tailPair.second)); + incoming[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + } + } + //find any active tail that needs to pass through to an incoming edge + //we expect to find no more than two pass through + + //find pass through with solid on top + { + //std::cout << "checking case 3\n"; + for(int i = 0; i < c_size; ++i) { + //std::cout << i << std::endl; + if(counts[i] != 0) { + if(counts[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = i_size_less_1; j >= 0; --j) { + if(incoming[j] != 0) { + if(incoming[j] == 1) { + //std::cout << "case3: " << i << " " << j << std::endl; + //tails[i]->print(); + //pass through solid on top + tails[i]->pushPoint(point); + //std::cout << "after push\n"; + if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + returnValue = tails[i]; + returnCount.first = point; + returnCount.second = -1; + } else { + elements.push_back(std::pair<vertex_half_edge, + active_tail_arbitrary*>(vertex_half_edge(point, + incoming_count[j].first, incoming[j]), tails[i])); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + } + //std::cout << "checking case 4\n"; + //find pass through with solid on bottom + { + for(int i = c_size_less_1; i >= 0; --i) { + //std::cout << "i = " << i << " with count " << counts[i] << std::endl; + if(counts[i] != 0) { + if(counts[i] == -1) { + for(int j = 0; j < i_size; ++j) { + if(incoming[j] != 0) { + if(incoming[j] == -1) { + //std::cout << "case4: " << i << " " << j << std::endl; + //pass through solid on bottom + tails[i]->pushPoint(point); + if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + returnValue = tails[i]; + returnCount.first = point; + returnCount.second = 1; + } else { + //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + //std::cout << point << " " << incoming_count[j].first << std::endl; + elements.push_back(std::pair<vertex_half_edge, + active_tail_arbitrary*>(vertex_half_edge(point, + incoming_count[j].first, incoming[j]), tails[i])); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + } + //find the end of a hole or the beginning of a hole + + //find end of a hole + { + for(int i = 0; i < c_size_less_1; ++i) { + if(counts[i] != 0) { + for(int j = i+1; j < c_size; ++j) { + if(counts[j] != 0) { + //std::cout << "case5: " << i << " " << j << std::endl; + //we are ending a hole and may potentially close a figure and have to handle the hole + returnValue = active_tail_arbitrary::joinChains(point, tails[i], tails[j], false, output); + if(returnValue) returnCount.first = point; + //std::cout << returnValue << std::endl; + tails[i] = 0; + tails[j] = 0; + counts[i] = 0; + counts[j] = 0; + break; + } + } + break; + } + } + } + //find beginning of a hole + { + for(int i = 0; i < i_size_less_1; ++i) { + if(incoming[i] != 0) { + for(int j = i+1; j < i_size; ++j) { + if(incoming[j] != 0) { + //std::cout << "case6: " << i << " " << j << std::endl; + //we are beginning a empty space + active_tail_arbitrary* holep = 0; + //if(c_size && counts[c_size_less_1] == 0 && + // counts_from_scanline[c_size_less_1].first.first.first.get(HORIZONTAL) == point.get(HORIZONTAL)) + if(have_vertical_tail_from_below) { + holep = tails[c_size_less_1]; + tails[c_size_less_1] = 0; + have_vertical_tail_from_below = false; + } + std::pair<active_tail_arbitrary*, active_tail_arbitrary*> tailPair = + active_tail_arbitrary::createActiveTailsAsPair(point, false, holep, fractureHoles_ != 0); + if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + //std::cout << "vertical element " << point << std::endl; + returnValue = tailPair.first; + returnCount.first = point; + //returnCount = incoming_count[j]; + returnCount.second = -1; + } else { + //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + //std::cout << point << " " << incoming_count[j].first << std::endl; + elements.push_back(std::pair<vertex_half_edge, + active_tail_arbitrary*>(vertex_half_edge(point, + incoming_count[j].first, incoming[j]), tailPair.first)); + } + //std::cout << "new element " << i-1 << " " << incoming[i] << std::endl; + //std::cout << point << " " << incoming_count[i].first << std::endl; + elements.push_back(std::pair<vertex_half_edge, + active_tail_arbitrary*>(vertex_half_edge(point, + incoming_count[i].first, incoming[i]), tailPair.second)); + incoming[i] = 0; + incoming[j] = 0; + break; + } + } + break; + } + } + } + if(have_vertical_tail_from_below) { + if(tails.back()) { + tails.back()->pushPoint(point); + returnValue = tails.back(); + returnCount.first = point; + returnCount.second = counts.back(); + } + } + //assert that tails, counts and incoming are all null + return std::pair<std::pair<Point, int>, active_tail_arbitrary*>(returnCount, returnValue); + } + + static inline void print(const vertex_arbitrary_count& count) { + for(unsigned i = 0; i < count.size(); ++i) { + //std::cout << count[i].first.get(HORIZONTAL) << ","; + //std::cout << count[i].first.get(VERTICAL) << ":"; + //std::cout << count[i].second << " "; + } //std::cout << std::endl; + } + + static inline void print(const scanline_data& data) { + for(typename scanline_data::const_iterator itr = data.begin(); itr != data.end(); ++itr){ + //std::cout << itr->first.pt << ", " << itr->first.other_pt << "; "; + } //std::cout << std::endl; + } + + template <class cT, class iT> + inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { + typedef typename high_precision_type<Unit>::type high_precision; + //std::cout << "processEvent_\n"; + justBefore_ = true; + //collect up all elements from the tree that are at the y + //values of events in the input queue + //create vector of new elements to add into tree + active_tail_arbitrary* verticalTail = 0; + std::pair<Point, int> verticalCount(Point(0, 0), 0); + iT currentIter = inputBegin; + std::vector<iterator> elementIters; + std::vector<std::pair<vertex_half_edge, active_tail_arbitrary*> > elements; + while(currentIter != inputEnd && currentIter->pt.get(HORIZONTAL) == x_) { + //std::cout << "loop\n"; + Unit currentY = (*currentIter).pt.get(VERTICAL); + //std::cout << "current Y " << currentY << std::endl; + //std::cout << "scanline size " << scanData_.size() << std::endl; + //print(scanData_); + iterator iter = lookUp_(currentY); + //std::cout << "found element in scanline " << (iter != scanData_.end()) << std::endl; + //int counts[4] = {0, 0, 0, 0}; + incoming_count counts_from_scanline; + //std::cout << "finding elements in tree\n"; + //if(iter != scanData_.end()) + // std::cout << "first iter y is " << iter->first.evalAtX(x_) << std::endl; + while(iter != scanData_.end() && + ((iter->first.pt.x() == x_ && iter->first.pt.y() == currentY) || + (iter->first.other_pt.x() == x_ && iter->first.other_pt.y() == currentY))) { + //iter->first.evalAtX(x_) == (high_precision)currentY) { + //std::cout << "loop2\n"; + elementIters.push_back(iter); + counts_from_scanline.push_back(std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*> + (std::pair<std::pair<Point, Point>, int>(std::pair<Point, Point>(iter->first.pt, + iter->first.other_pt), + iter->first.count), + iter->second)); + ++iter; + } + Point currentPoint(x_, currentY); + //std::cout << "counts_from_scanline size " << counts_from_scanline.size() << std::endl; + sort_incoming_count(counts_from_scanline, currentPoint); + + vertex_arbitrary_count incoming; + //std::cout << "aggregating\n"; + do { + //std::cout << "loop3\n"; + const vertex_half_edge& elem = *currentIter; + incoming.push_back(std::pair<Point, int>(elem.other_pt, elem.count)); + ++currentIter; + } while(currentIter != inputEnd && currentIter->pt.get(VERTICAL) == currentY && + currentIter->pt.get(HORIZONTAL) == x_); + //print(incoming); + sort_vertex_arbitrary_count(incoming, currentPoint); + //std::cout << currentPoint.get(HORIZONTAL) << "," << currentPoint.get(VERTICAL) << std::endl; + //print(incoming); + //std::cout << "incoming counts from input size " << incoming.size() << std::endl; + //compact_vertex_arbitrary_count(currentPoint, incoming); + vertex_arbitrary_count tmp; + tmp.reserve(incoming.size()); + for(std::size_t i = 0; i < incoming.size(); ++i) { + if(currentPoint < incoming[i].first) { + tmp.push_back(incoming[i]); + } + } + incoming.swap(tmp); + //std::cout << "incoming counts from input size " << incoming.size() << std::endl; + //now counts_from_scanline has the data from the left and + //incoming has the data from the right at this point + //cancel out any end points + if(verticalTail) { + //std::cout << "adding vertical tail to counts from scanline\n"; + //std::cout << -verticalCount.second << std::endl; + counts_from_scanline.push_back(std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*> + (std::pair<std::pair<Point, Point>, int>(std::pair<Point, Point>(verticalCount.first, + currentPoint), + -verticalCount.second), + verticalTail)); + } + if(!incoming.empty() && incoming.back().first.get(HORIZONTAL) == x_) { + //std::cout << "inverted vertical event\n"; + incoming.back().second *= -1; + } + //std::cout << "calling processPoint_\n"; + std::pair<std::pair<Point, int>, active_tail_arbitrary*> result = processPoint_(output, elements, Point(x_, currentY), counts_from_scanline, incoming); + verticalCount = result.first; + verticalTail = result.second; + //if(verticalTail) { + // std::cout << "have vertical tail\n"; + // std::cout << verticalCount.second << std::endl; + //} + if(verticalTail && !(verticalCount.second)) { + //we got a hole out of the point we just processed + //iter is still at the next y element above the current y value in the tree + //std::cout << "checking whether ot handle hole\n"; + if(currentIter == inputEnd || + currentIter->pt.get(HORIZONTAL) != x_ || + scanline_base<Unit>::on_above_or_below(currentIter->pt, half_edge(iter->first.pt, iter->first.other_pt)) != -1) { + //(high_precision)(currentIter->pt.get(VERTICAL)) >= iter->first.evalAtX(x_)) { + + //std::cout << "handle hole here\n"; + if(fractureHoles_) { + //std::cout << "fracture hole here\n"; + //we need to handle the hole now and not at the next input vertex + active_tail_arbitrary* at = iter->second; + high_precision precise_y = iter->first.evalAtX(x_); + Unit fracture_y = convert_high_precision_type<Unit>(precise_y); + if(precise_y < fracture_y) --fracture_y; + Point point(x_, fracture_y); + verticalTail->getOtherActiveTail()->pushPoint(point); + iter->second = verticalTail->getOtherActiveTail(); + at->pushPoint(point); + verticalTail->join(at); + delete at; + delete verticalTail; + verticalTail = 0; + } else { + //std::cout << "push hole onto list\n"; + iter->second->addHole(verticalTail); + verticalTail = 0; + } + } + } + } + //std::cout << "erasing\n"; + //erase all elements from the tree + for(typename std::vector<iterator>::iterator iter = elementIters.begin(); + iter != elementIters.end(); ++iter) { + //std::cout << "erasing loop\n"; + scanData_.erase(*iter); + } + //switch comparison tie breaking policy + justBefore_ = false; + //add new elements into tree + //std::cout << "inserting\n"; + for(typename std::vector<std::pair<vertex_half_edge, active_tail_arbitrary*> >::iterator iter = elements.begin(); + iter != elements.end(); ++iter) { + //std::cout << "inserting loop\n"; + scanData_.insert(scanData_.end(), *iter); + } + //std::cout << "end processEvent\n"; + return currentIter; + } + + inline iterator lookUp_(Unit y){ + //if just before then we need to look from 1 not -1 + //std::cout << "just before " << justBefore_ << std::endl; + return scanData_.lower_bound(vertex_half_edge(Point(x_, y), Point(x_, y+1), 0)); + } + + public: //test functions + + template <typename stream_type> + static inline bool testPolygonArbitraryFormationRect(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + polygon_arbitrary_formation pf(true); + std::vector<polygon_data<Unit> > polys; + std::vector<vertex_half_edge> data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(10, 10), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(10, 10), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(0, 10), 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygonArbitraryFormationP1(stream_type& stdcout) { + stdcout << "testing polygon formation P1\n"; + polygon_arbitrary_formation pf(true); + std::vector<polygon_data<Unit> > polys; + std::vector<vertex_half_edge> data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(10, 20), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(10, 20), -1)); + data.push_back(vertex_half_edge(Point(10, 20), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(10, 20), Point(0, 10), 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygonArbitraryFormationP2(stream_type& stdcout) { + stdcout << "testing polygon formation P2\n"; + polygon_arbitrary_formation pf(true); + std::vector<polygon_data<Unit> > polys; + std::vector<vertex_half_edge> data; + data.push_back(vertex_half_edge(Point(-3, 1), Point(2, -4), 1)); + data.push_back(vertex_half_edge(Point(-3, 1), Point(-2, 2), -1)); + data.push_back(vertex_half_edge(Point(-2, 2), Point(2, 4), -1)); + data.push_back(vertex_half_edge(Point(-2, 2), Point(-3, 1), 1)); + data.push_back(vertex_half_edge(Point(2, -4), Point(-3, 1), -1)); + data.push_back(vertex_half_edge(Point(2, -4), Point(2, 4), -1)); + data.push_back(vertex_half_edge(Point(2, 4), Point(-2, 2), 1)); + data.push_back(vertex_half_edge(Point(2, 4), Point(2, -4), 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + + template <typename stream_type> + static inline bool testPolygonArbitraryFormationPolys(stream_type& stdcout) { + stdcout << "testing polygon formation polys\n"; + polygon_arbitrary_formation pf(false); + std::vector<polygon_with_holes_data<Unit> > polys; + polygon_arbitrary_formation pf2(true); + std::vector<polygon_with_holes_data<Unit> > polys2; + std::vector<vertex_half_edge> data; + data.push_back(vertex_half_edge(Point(0, 0), Point(100, 1), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(1, 100), -1)); + data.push_back(vertex_half_edge(Point(1, 100), Point(0, 0), 1)); + data.push_back(vertex_half_edge(Point(1, 100), Point(101, 101), -1)); + data.push_back(vertex_half_edge(Point(100, 1), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(100, 1), Point(101, 101), 1)); + data.push_back(vertex_half_edge(Point(101, 101), Point(100, 1), -1)); + data.push_back(vertex_half_edge(Point(101, 101), Point(1, 100), 1)); + + data.push_back(vertex_half_edge(Point(2, 2), Point(10, 2), -1)); + data.push_back(vertex_half_edge(Point(2, 2), Point(2, 10), -1)); + data.push_back(vertex_half_edge(Point(2, 10), Point(2, 2), 1)); + data.push_back(vertex_half_edge(Point(2, 10), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(10, 2), Point(2, 2), 1)); + data.push_back(vertex_half_edge(Point(10, 2), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(10, 2), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(2, 10), -1)); + + data.push_back(vertex_half_edge(Point(2, 12), Point(10, 12), -1)); + data.push_back(vertex_half_edge(Point(2, 12), Point(2, 22), -1)); + data.push_back(vertex_half_edge(Point(2, 22), Point(2, 12), 1)); + data.push_back(vertex_half_edge(Point(2, 22), Point(10, 22), 1)); + data.push_back(vertex_half_edge(Point(10, 12), Point(2, 12), 1)); + data.push_back(vertex_half_edge(Point(10, 12), Point(10, 22), 1)); + data.push_back(vertex_half_edge(Point(10, 22), Point(10, 12), -1)); + data.push_back(vertex_half_edge(Point(10, 22), Point(2, 22), -1)); + + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + pf2.scan(polys2, data.begin(), data.end()); + stdcout << "result size: " << polys2.size() << std::endl; + for(std::size_t i = 0; i < polys2.size(); ++i) { + stdcout << polys2[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygonArbitraryFormationSelfTouch1(stream_type& stdcout) { + stdcout << "testing polygon formation self touch 1\n"; + polygon_arbitrary_formation pf(true); + std::vector<polygon_data<Unit> > polys; + std::vector<vertex_half_edge> data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(5, 10), -1)); + + data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(10, 5), -1)); + + data.push_back(vertex_half_edge(Point(10, 5), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(10, 5), Point(5, 5), 1)); + + data.push_back(vertex_half_edge(Point(5, 10), Point(5, 5), 1)); + data.push_back(vertex_half_edge(Point(5, 10), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(5, 2), Point(5, 5), -1)); + data.push_back(vertex_half_edge(Point(5, 2), Point(7, 2), -1)); + + data.push_back(vertex_half_edge(Point(5, 5), Point(5, 10), -1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(5, 2), 1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); + + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 2), 1)); + + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygonArbitraryFormationSelfTouch2(stream_type& stdcout) { + stdcout << "testing polygon formation self touch 2\n"; + polygon_arbitrary_formation pf(true); + std::vector<polygon_data<Unit> > polys; + std::vector<vertex_half_edge> data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(5, 10), -1)); + + data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(10, 5), -1)); + + data.push_back(vertex_half_edge(Point(10, 5), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(10, 5), Point(5, 5), 1)); + + data.push_back(vertex_half_edge(Point(5, 10), Point(4, 1), -1)); + data.push_back(vertex_half_edge(Point(5, 10), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(4, 1), Point(5, 10), 1)); + data.push_back(vertex_half_edge(Point(4, 1), Point(7, 2), -1)); + + data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); + + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); + data.push_back(vertex_half_edge(Point(7, 2), Point(4, 1), 1)); + + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygonArbitraryFormationSelfTouch3(stream_type& stdcout) { + stdcout << "testing polygon formation self touch 3\n"; + polygon_arbitrary_formation pf(true); + std::vector<polygon_data<Unit> > polys; + std::vector<vertex_half_edge> data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(6, 10), -1)); + + data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(10, 5), -1)); + + data.push_back(vertex_half_edge(Point(10, 5), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(10, 5), Point(5, 5), 1)); + + data.push_back(vertex_half_edge(Point(6, 10), Point(4, 1), -1)); + data.push_back(vertex_half_edge(Point(6, 10), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(4, 1), Point(6, 10), 1)); + data.push_back(vertex_half_edge(Point(4, 1), Point(7, 2), -1)); + + data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); + + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); + data.push_back(vertex_half_edge(Point(7, 2), Point(4, 1), 1)); + + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template <typename stream_type> + static inline bool testPolygonArbitraryFormationColinear(stream_type& stdcout) { + stdcout << "testing polygon formation colinear 3\n"; + stdcout << "Polygon Set Data { <-3 2, -2 2>:1 <-3 2, -1 4>:-1 <-2 2, 0 2>:1 <-1 4, 0 2>:-1 } \n"; + polygon_arbitrary_formation pf(true); + std::vector<polygon_data<Unit> > polys; + std::vector<vertex_half_edge> data; + data.push_back(vertex_half_edge(Point(-3, 2), Point(-2, 2), 1)); + data.push_back(vertex_half_edge(Point(-2, 2), Point(-3, 2), -1)); + + data.push_back(vertex_half_edge(Point(-3, 2), Point(-1, 4), -1)); + data.push_back(vertex_half_edge(Point(-1, 4), Point(-3, 2), 1)); + + data.push_back(vertex_half_edge(Point(-2, 2), Point(0, 2), 1)); + data.push_back(vertex_half_edge(Point(0, 2), Point(-2, 2), -1)); + + data.push_back(vertex_half_edge(Point(-1, 4), Point(0, 2), -1)); + data.push_back(vertex_half_edge(Point(0, 2), Point(-1, 4), 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template <typename stream_type> + static inline bool testSegmentIntersection(stream_type& stdcout) { + stdcout << "testing segment intersection\n"; + half_edge he1, he2; + he1.first = Point(0, 0); + he1.second = Point(10, 10); + he2.first = Point(0, 0); + he2.second = Point(10, 20); + Point result; + bool b = scanline_base<Unit>::compute_intersection(result, he1, he2); + if(!b || result != Point(0, 0)) return false; + he1.first = Point(0, 10); + b = scanline_base<Unit>::compute_intersection(result, he1, he2); + if(!b || result != Point(5, 10)) return false; + he1.first = Point(0, 11); + b = scanline_base<Unit>::compute_intersection(result, he1, he2); + if(!b || result != Point(5, 10)) return false; + he1.first = Point(0, 0); + he1.second = Point(1, 9); + he2.first = Point(0, 9); + he2.second = Point(1, 0); + b = scanline_base<Unit>::compute_intersection(result, he1, he2); + if(!b || result != Point(0, 4)) return false; + + he1.first = Point(0, -10); + he1.second = Point(1, -1); + he2.first = Point(0, -1); + he2.second = Point(1, -10); + b = scanline_base<Unit>::compute_intersection(result, he1, he2); + if(!b || result != Point(0, -5)) return false; + he1.first = Point((std::numeric_limits<int>::max)(), (std::numeric_limits<int>::max)()-1); + he1.second = Point((std::numeric_limits<int>::min)(), (std::numeric_limits<int>::max)()); + //he1.second = Point(0, (std::numeric_limits<int>::max)()); + he2.first = Point((std::numeric_limits<int>::max)()-1, (std::numeric_limits<int>::max)()); + he2.second = Point((std::numeric_limits<int>::max)(), (std::numeric_limits<int>::min)()); + //he2.second = Point((std::numeric_limits<int>::max)(), 0); + b = scanline_base<Unit>::compute_intersection(result, he1, he2); + //b is false because of overflow error + he1.first = Point(1000, 2000); + he1.second = Point(1010, 2010); + he2.first = Point(1000, 2000); + he2.second = Point(1010, 2020); + b = scanline_base<Unit>::compute_intersection(result, he1, he2); + if(!b || result != Point(1000, 2000)) return false; + + return b; + } + + }; + + template <typename Unit> + class poly_line_arbitrary_hole_data { + private: + typedef typename polygon_arbitrary_formation<Unit>::active_tail_arbitrary active_tail_arbitrary; + active_tail_arbitrary* p_; + public: + typedef point_data<Unit> Point; + typedef Point point_type; + typedef Unit coordinate_type; + typedef typename active_tail_arbitrary::iterator iterator_type; + //typedef iterator_points_to_compact<iterator_type, Point> compact_iterator_type; + + typedef iterator_type iterator; + inline poly_line_arbitrary_hole_data() : p_(0) {} + inline poly_line_arbitrary_hole_data(active_tail_arbitrary* p) : p_(p) {} + //use default copy and assign + inline iterator begin() const { return p_->getTail()->begin(); } + inline iterator end() const { return p_->getTail()->end(); } + //inline compact_iterator_type begin_compact() const { return compact_iterator_type(begin()); } + //inline compact_iterator_type end_compact() const { return compact_iterator_type(end()); } + inline std::size_t size() const { return 0; } + template<class iT> + inline poly_line_arbitrary_hole_data& set(iT inputBegin, iT inputEnd) { + //assert this is not called + return *this; + } + template<class iT> + inline poly_line_arbitrary_hole_data& set_compact(iT inputBegin, iT inputEnd) { + //assert this is not called + return *this; + } + }; + + template <typename Unit> + class poly_line_arbitrary_polygon_data { + private: + typedef typename polygon_arbitrary_formation<Unit>::active_tail_arbitrary active_tail_arbitrary; + active_tail_arbitrary* p_; + public: + typedef point_data<Unit> Point; + typedef Point point_type; + typedef Unit coordinate_type; + typedef typename active_tail_arbitrary::iterator iterator_type; + //typedef iterator_points_to_compact<iterator_type, Point> compact_iterator_type; + typedef typename coordinate_traits<Unit>::coordinate_distance area_type; + + class iterator_holes_type { + private: + typedef poly_line_arbitrary_hole_data<Unit> holeType; + mutable holeType hole_; + typename active_tail_arbitrary::iteratorHoles itr_; + + public: + typedef std::forward_iterator_tag iterator_category; + typedef holeType value_type; + typedef std::ptrdiff_t difference_type; + typedef const holeType* pointer; //immutable + typedef const holeType& reference; //immutable + inline iterator_holes_type() : hole_(), itr_() {} + inline iterator_holes_type(typename active_tail_arbitrary::iteratorHoles itr) : hole_(), itr_(itr) {} + inline iterator_holes_type(const iterator_holes_type& that) : hole_(that.hole_), itr_(that.itr_) {} + inline iterator_holes_type& operator=(const iterator_holes_type& that) { + itr_ = that.itr_; + return *this; + } + inline bool operator==(const iterator_holes_type& that) { return itr_ == that.itr_; } + inline bool operator!=(const iterator_holes_type& that) { return itr_ != that.itr_; } + inline iterator_holes_type& operator++() { + ++itr_; + return *this; + } + inline const iterator_holes_type operator++(int) { + iterator_holes_type tmp = *this; + ++(*this); + return tmp; + } + inline reference operator*() { + hole_ = holeType(*itr_); + return hole_; + } + }; + + typedef poly_line_arbitrary_hole_data<Unit> hole_type; + + inline poly_line_arbitrary_polygon_data() : p_(0) {} + inline poly_line_arbitrary_polygon_data(active_tail_arbitrary* p) : p_(p) {} + //use default copy and assign + inline iterator_type begin() const { return p_->getTail()->begin(); } + inline iterator_type end() const { return p_->getTail()->end(); } + //inline compact_iterator_type begin_compact() const { return p_->getTail()->begin(); } + //inline compact_iterator_type end_compact() const { return p_->getTail()->end(); } + inline iterator_holes_type begin_holes() const { return iterator_holes_type(p_->getHoles().begin()); } + inline iterator_holes_type end_holes() const { return iterator_holes_type(p_->getHoles().end()); } + inline active_tail_arbitrary* yield() { return p_; } + //stub out these four required functions that will not be used but are needed for the interface + inline std::size_t size_holes() const { return 0; } + inline std::size_t size() const { return 0; } + template<class iT> + inline poly_line_arbitrary_polygon_data& set(iT inputBegin, iT inputEnd) { + return *this; + } + template<class iT> + inline poly_line_arbitrary_polygon_data& set_compact(iT inputBegin, iT inputEnd) { + return *this; + } + template<class iT> + inline poly_line_arbitrary_polygon_data& set_holes(iT inputBegin, iT inputEnd) { + return *this; + } + }; + + template <typename Unit> + class trapezoid_arbitrary_formation : public polygon_arbitrary_formation<Unit> { + private: + typedef typename scanline_base<Unit>::Point Point; + typedef typename scanline_base<Unit>::half_edge half_edge; + typedef typename scanline_base<Unit>::vertex_half_edge vertex_half_edge; + typedef typename scanline_base<Unit>::less_vertex_half_edge less_vertex_half_edge; + + typedef typename polygon_arbitrary_formation<Unit>::poly_line_arbitrary poly_line_arbitrary; + + typedef typename polygon_arbitrary_formation<Unit>::active_tail_arbitrary active_tail_arbitrary; + + typedef std::vector<std::pair<Point, int> > vertex_arbitrary_count; + + typedef typename polygon_arbitrary_formation<Unit>::less_half_edge_count less_half_edge_count; + + typedef std::vector<std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*> > incoming_count; + + typedef typename polygon_arbitrary_formation<Unit>::less_incoming_count less_incoming_count; + + typedef typename polygon_arbitrary_formation<Unit>::vertex_arbitrary_compact vertex_arbitrary_compact; + + private: + //definitions + typedef std::map<vertex_half_edge, active_tail_arbitrary*, less_vertex_half_edge> scanline_data; + typedef typename scanline_data::iterator iterator; + typedef typename scanline_data::const_iterator const_iterator; + + //data + public: + inline trapezoid_arbitrary_formation() : polygon_arbitrary_formation<Unit>() {} + inline trapezoid_arbitrary_formation(const trapezoid_arbitrary_formation& that) : polygon_arbitrary_formation<Unit>(that) {} + inline trapezoid_arbitrary_formation& operator=(const trapezoid_arbitrary_formation& that) { + * static_cast<polygon_arbitrary_formation<Unit>*>(this) = * static_cast<polygon_arbitrary_formation<Unit>*>(&that); + return *this; + } + + //cT is an output container of Polygon45 or Polygon45WithHoles + //iT is an iterator over vertex_half_edge elements + //inputBegin - inputEnd is a range of sorted iT that represents + //one or more scanline stops worth of data + template <class cT, class iT> + void scan(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "1\n"; + while(inputBegin != inputEnd) { + //std::cout << "2\n"; + polygon_arbitrary_formation<Unit>::x_ = (*inputBegin).pt.get(HORIZONTAL); + //std::cout << "SCAN FORMATION " << x_ << std::endl; + //std::cout << "x_ = " << x_ << std::endl; + //std::cout << "scan line size: " << scanData_.size() << std::endl; + inputBegin = processEvent_(output, inputBegin, inputEnd); + } + //std::cout << "scan line size: " << scanData_.size() << std::endl; + } + + private: + //functions + inline void getVerticalPair_(std::pair<active_tail_arbitrary*, + active_tail_arbitrary*>& verticalPair, + iterator previter) { + active_tail_arbitrary* iterTail = (*previter).second; + Point prevPoint(polygon_arbitrary_formation<Unit>::x_, + convert_high_precision_type<Unit>(previter->first.evalAtX(polygon_arbitrary_formation<Unit>::x_))); + iterTail->pushPoint(prevPoint); + std::pair<active_tail_arbitrary*, active_tail_arbitrary*> tailPair = + active_tail_arbitrary::createActiveTailsAsPair(prevPoint, true, 0, false); + verticalPair.first = iterTail; + verticalPair.second = tailPair.first; + (*previter).second = tailPair.second; + } + + template <class cT, class cT2> + inline std::pair<std::pair<Point, int>, active_tail_arbitrary*> + processPoint_(cT& output, cT2& elements, + std::pair<active_tail_arbitrary*, active_tail_arbitrary*>& verticalPair, + iterator previter, Point point, incoming_count& counts_from_scanline, + vertex_arbitrary_count& incoming_count) { + //std::cout << "\nAT POINT: " << point << std::endl; + //join any closing solid corners + std::vector<int> counts; + std::vector<int> incoming; + std::vector<active_tail_arbitrary*> tails; + counts.reserve(counts_from_scanline.size()); + tails.reserve(counts_from_scanline.size()); + incoming.reserve(incoming_count.size()); + for(std::size_t i = 0; i < counts_from_scanline.size(); ++i) { + counts.push_back(counts_from_scanline[i].first.second); + tails.push_back(counts_from_scanline[i].second); + } + for(std::size_t i = 0; i < incoming_count.size(); ++i) { + incoming.push_back(incoming_count[i].second); + if(incoming_count[i].first < point) { + incoming.back() = 0; + } + } + + active_tail_arbitrary* returnValue = 0; + std::pair<active_tail_arbitrary*, active_tail_arbitrary*> verticalPairOut; + verticalPairOut.first = 0; + verticalPairOut.second = 0; + std::pair<Point, int> returnCount(Point(0, 0), 0); + int i_size_less_1 = (int)(incoming.size()) -1; + int c_size_less_1 = (int)(counts.size()) -1; + int i_size = incoming.size(); + int c_size = counts.size(); + + bool have_vertical_tail_from_below = false; + if(c_size && + scanline_base<Unit>::is_vertical(counts_from_scanline.back().first.first)) { + have_vertical_tail_from_below = true; + } + //assert size = size_less_1 + 1 + //std::cout << tails.size() << " " << incoming.size() << " " << counts_from_scanline.size() << " " << incoming_count.size() << std::endl; + // for(std::size_t i = 0; i < counts.size(); ++i) { + // std::cout << counts_from_scanline[i].first.first.first.get(HORIZONTAL) << ","; + // std::cout << counts_from_scanline[i].first.first.first.get(VERTICAL) << " "; + // std::cout << counts_from_scanline[i].first.first.second.get(HORIZONTAL) << ","; + // std::cout << counts_from_scanline[i].first.first.second.get(VERTICAL) << ":"; + // std::cout << counts_from_scanline[i].first.second << " "; + // } std::cout << std::endl; + // print(incoming_count); + { + for(int i = 0; i < c_size_less_1; ++i) { + //std::cout << i << std::endl; + if(counts[i] == -1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < c_size; ++j) { + //std::cout << j << std::endl; + if(counts[j]) { + if(counts[j] == 1) { + //std::cout << "case1: " << i << " " << j << std::endl; + //if a figure is closed it will be written out by this function to output + active_tail_arbitrary::joinChains(point, tails[i], tails[j], true, output); + counts[i] = 0; + counts[j] = 0; + tails[i] = 0; + tails[j] = 0; + } + break; + } + } + } + } + } + //find any pairs of incoming edges that need to create pair for leading solid + //std::cout << "checking case2\n"; + { + for(int i = 0; i < i_size_less_1; ++i) { + //std::cout << i << std::endl; + if(incoming[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < i_size; ++j) { + //std::cout << j << std::endl; + if(incoming[j]) { + //std::cout << incoming[j] << std::endl; + if(incoming[j] == -1) { + //std::cout << "case2: " << i << " " << j << std::endl; + //std::cout << "creating active tail pair\n"; + std::pair<active_tail_arbitrary*, active_tail_arbitrary*> tailPair = + active_tail_arbitrary::createActiveTailsAsPair(point, true, 0, polygon_arbitrary_formation<Unit>::fractureHoles_ != 0); + //tailPair.first->print(); + //tailPair.second->print(); + if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + //vertical active tail becomes return value + returnValue = tailPair.first; + returnCount.first = point; + returnCount.second = 1; + } else { + //std::cout << "new element " << j-1 << " " << -1 << std::endl; + //std::cout << point << " " << incoming_count[j].first << std::endl; + elements.push_back(std::pair<vertex_half_edge, + active_tail_arbitrary*>(vertex_half_edge(point, + incoming_count[j].first, -1), tailPair.first)); + } + //std::cout << "new element " << i-1 << " " << 1 << std::endl; + //std::cout << point << " " << incoming_count[i].first << std::endl; + elements.push_back(std::pair<vertex_half_edge, + active_tail_arbitrary*>(vertex_half_edge(point, + incoming_count[i].first, 1), tailPair.second)); + incoming[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + } + } + //find any active tail that needs to pass through to an incoming edge + //we expect to find no more than two pass through + + //find pass through with solid on top + { + //std::cout << "checking case 3\n"; + for(int i = 0; i < c_size; ++i) { + //std::cout << i << std::endl; + if(counts[i] != 0) { + if(counts[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = i_size_less_1; j >= 0; --j) { + if(incoming[j] != 0) { + if(incoming[j] == 1) { + //std::cout << "case3: " << i << " " << j << std::endl; + //tails[i]->print(); + //pass through solid on top + tails[i]->pushPoint(point); + //std::cout << "after push\n"; + if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + returnValue = tails[i]; + returnCount.first = point; + returnCount.second = -1; + } else { + std::pair<active_tail_arbitrary*, active_tail_arbitrary*> tailPair = + active_tail_arbitrary::createActiveTailsAsPair(point, true, 0, false); + verticalPairOut.first = tails[i]; + verticalPairOut.second = tailPair.first; + elements.push_back(std::pair<vertex_half_edge, + active_tail_arbitrary*>(vertex_half_edge(point, + incoming_count[j].first, incoming[j]), tailPair.second)); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + } + //std::cout << "checking case 4\n"; + //find pass through with solid on bottom + { + for(int i = c_size_less_1; i >= 0; --i) { + //std::cout << "i = " << i << " with count " << counts[i] << std::endl; + if(counts[i] != 0) { + if(counts[i] == -1) { + for(int j = 0; j < i_size; ++j) { + if(incoming[j] != 0) { + if(incoming[j] == -1) { + //std::cout << "case4: " << i << " " << j << std::endl; + //pass through solid on bottom + + //if count from scanline is vertical + if(i == c_size_less_1 && + counts_from_scanline[i].first.first.first.get(HORIZONTAL) == + point.get(HORIZONTAL)) { + //if incoming count is vertical + if(j == i_size_less_1 && + incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + returnValue = tails[i]; + returnCount.first = point; + returnCount.second = 1; + } else { + tails[i]->pushPoint(point); + elements.push_back(std::pair<vertex_half_edge, + active_tail_arbitrary*>(vertex_half_edge(point, + incoming_count[j].first, incoming[j]), tails[i])); + } + } else if(j == i_size_less_1 && + incoming_count[j].first.get(HORIZONTAL) == + point.get(HORIZONTAL)) { + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + active_tail_arbitrary::joinChains(point, tails[i], verticalPair.first, true, output); + returnValue = verticalPair.second; + returnCount.first = point; + returnCount.second = 1; + } else { + //neither is vertical + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + active_tail_arbitrary::joinChains(point, tails[i], verticalPair.first, true, output); + verticalPair.second->pushPoint(point); + elements.push_back(std::pair<vertex_half_edge, + active_tail_arbitrary*>(vertex_half_edge(point, + incoming_count[j].first, incoming[j]), verticalPair.second)); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + } + //find the end of a hole or the beginning of a hole + + //find end of a hole + { + for(int i = 0; i < c_size_less_1; ++i) { + if(counts[i] != 0) { + for(int j = i+1; j < c_size; ++j) { + if(counts[j] != 0) { + //std::cout << "case5: " << i << " " << j << std::endl; + //we are ending a hole and may potentially close a figure and have to handle the hole + tails[i]->pushPoint(point); + verticalPairOut.first = tails[i]; + if(j == c_size_less_1 && + counts_from_scanline[j].first.first.first.get(HORIZONTAL) == + point.get(HORIZONTAL)) { + verticalPairOut.second = tails[j]; + } else { + //need to close a trapezoid below + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + active_tail_arbitrary::joinChains(point, tails[j], verticalPair.first, true, output); + verticalPairOut.second = verticalPair.second; + } + tails[i] = 0; + tails[j] = 0; + counts[i] = 0; + counts[j] = 0; + break; + } + } + break; + } + } + } + //find beginning of a hole + { + for(int i = 0; i < i_size_less_1; ++i) { + if(incoming[i] != 0) { + for(int j = i+1; j < i_size; ++j) { + if(incoming[j] != 0) { + //std::cout << "case6: " << i << " " << j << std::endl; + //we are beginning a empty space + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + verticalPair.second->pushPoint(point); + if(j == i_size_less_1 && + incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + returnValue = verticalPair.first; + returnCount.first = point; + returnCount.second = -1; + } else { + std::pair<active_tail_arbitrary*, active_tail_arbitrary*> tailPair = + active_tail_arbitrary::createActiveTailsAsPair(point, false, 0, false); + elements.push_back(std::pair<vertex_half_edge, + active_tail_arbitrary*>(vertex_half_edge(point, + incoming_count[j].first, incoming[j]), tailPair.second)); + verticalPairOut.second = tailPair.first; + verticalPairOut.first = verticalPair.first; + } + elements.push_back(std::pair<vertex_half_edge, + active_tail_arbitrary*>(vertex_half_edge(point, + incoming_count[i].first, incoming[i]), verticalPair.second)); + incoming[i] = 0; + incoming[j] = 0; + break; + } + } + break; + } + } + } + if(have_vertical_tail_from_below) { + if(tails.back()) { + tails.back()->pushPoint(point); + returnValue = tails.back(); + returnCount.first = point; + returnCount.second = counts.back(); + } + } + verticalPair = verticalPairOut; + //assert that tails, counts and incoming are all null + return std::pair<std::pair<Point, int>, active_tail_arbitrary*>(returnCount, returnValue); + } + + static inline void print(const vertex_arbitrary_count& count) { + for(unsigned i = 0; i < count.size(); ++i) { + //std::cout << count[i].first.get(HORIZONTAL) << ","; + //std::cout << count[i].first.get(VERTICAL) << ":"; + //std::cout << count[i].second << " "; + } //std::cout << std::endl; + } + + static inline void print(const scanline_data& data) { + for(typename scanline_data::const_iterator itr = data.begin(); itr != data.end(); ++itr){ + //std::cout << itr->first.pt << ", " << itr->first.other_pt << "; "; + } //std::cout << std::endl; + } + + template <class cT, class iT> + inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { + typedef typename high_precision_type<Unit>::type high_precision; + //std::cout << "processEvent_\n"; + polygon_arbitrary_formation<Unit>::justBefore_ = true; + //collect up all elements from the tree that are at the y + //values of events in the input queue + //create vector of new elements to add into tree + active_tail_arbitrary* verticalTail = 0; + std::pair<active_tail_arbitrary*, active_tail_arbitrary*> verticalPair; + std::pair<Point, int> verticalCount(Point(0, 0), 0); + iT currentIter = inputBegin; + std::vector<iterator> elementIters; + std::vector<std::pair<vertex_half_edge, active_tail_arbitrary*> > elements; + while(currentIter != inputEnd && currentIter->pt.get(HORIZONTAL) == polygon_arbitrary_formation<Unit>::x_) { + //std::cout << "loop\n"; + Unit currentY = (*currentIter).pt.get(VERTICAL); + //std::cout << "current Y " << currentY << std::endl; + //std::cout << "scanline size " << scanData_.size() << std::endl; + //print(scanData_); + iterator iter = this->lookUp_(currentY); + //std::cout << "found element in scanline " << (iter != scanData_.end()) << std::endl; + //int counts[4] = {0, 0, 0, 0}; + incoming_count counts_from_scanline; + //std::cout << "finding elements in tree\n"; + //if(iter != scanData_.end()) + // std::cout << "first iter y is " << iter->first.evalAtX(x_) << std::endl; + iterator previter = iter; + if(previter != polygon_arbitrary_formation<Unit>::scanData_.end() && + previter->first.evalAtX(polygon_arbitrary_formation<Unit>::x_) >= currentY && + previter != polygon_arbitrary_formation<Unit>::scanData_.begin()) + --previter; + while(iter != polygon_arbitrary_formation<Unit>::scanData_.end() && + ((iter->first.pt.x() == polygon_arbitrary_formation<Unit>::x_ && iter->first.pt.y() == currentY) || + (iter->first.other_pt.x() == polygon_arbitrary_formation<Unit>::x_ && iter->first.other_pt.y() == currentY))) { + //iter->first.evalAtX(polygon_arbitrary_formation<Unit>::x_) == (high_precision)currentY) { + //std::cout << "loop2\n"; + elementIters.push_back(iter); + counts_from_scanline.push_back(std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*> + (std::pair<std::pair<Point, Point>, int>(std::pair<Point, Point>(iter->first.pt, + iter->first.other_pt), + iter->first.count), + iter->second)); + ++iter; + } + Point currentPoint(polygon_arbitrary_formation<Unit>::x_, currentY); + //std::cout << "counts_from_scanline size " << counts_from_scanline.size() << std::endl; + this->sort_incoming_count(counts_from_scanline, currentPoint); + + vertex_arbitrary_count incoming; + //std::cout << "aggregating\n"; + do { + //std::cout << "loop3\n"; + const vertex_half_edge& elem = *currentIter; + incoming.push_back(std::pair<Point, int>(elem.other_pt, elem.count)); + ++currentIter; + } while(currentIter != inputEnd && currentIter->pt.get(VERTICAL) == currentY && + currentIter->pt.get(HORIZONTAL) == polygon_arbitrary_formation<Unit>::x_); + //print(incoming); + this->sort_vertex_arbitrary_count(incoming, currentPoint); + //std::cout << currentPoint.get(HORIZONTAL) << "," << currentPoint.get(VERTICAL) << std::endl; + //print(incoming); + //std::cout << "incoming counts from input size " << incoming.size() << std::endl; + //compact_vertex_arbitrary_count(currentPoint, incoming); + vertex_arbitrary_count tmp; + tmp.reserve(incoming.size()); + for(std::size_t i = 0; i < incoming.size(); ++i) { + if(currentPoint < incoming[i].first) { + tmp.push_back(incoming[i]); + } + } + incoming.swap(tmp); + //std::cout << "incoming counts from input size " << incoming.size() << std::endl; + //now counts_from_scanline has the data from the left and + //incoming has the data from the right at this point + //cancel out any end points + if(verticalTail) { + //std::cout << "adding vertical tail to counts from scanline\n"; + //std::cout << -verticalCount.second << std::endl; + counts_from_scanline.push_back(std::pair<std::pair<std::pair<Point, Point>, int>, active_tail_arbitrary*> + (std::pair<std::pair<Point, Point>, int>(std::pair<Point, Point>(verticalCount.first, + currentPoint), + -verticalCount.second), + verticalTail)); + } + if(!incoming.empty() && incoming.back().first.get(HORIZONTAL) == polygon_arbitrary_formation<Unit>::x_) { + //std::cout << "inverted vertical event\n"; + incoming.back().second *= -1; + } + //std::cout << "calling processPoint_\n"; + std::pair<std::pair<Point, int>, active_tail_arbitrary*> result = processPoint_(output, elements, verticalPair, previter, Point(polygon_arbitrary_formation<Unit>::x_, currentY), counts_from_scanline, incoming); + verticalCount = result.first; + verticalTail = result.second; + if(verticalPair.first != 0 && iter != polygon_arbitrary_formation<Unit>::scanData_.end() && + (currentIter == inputEnd || currentIter->pt.x() != polygon_arbitrary_formation<Unit>::x_ || + currentIter->pt.y() > (*iter).first.evalAtX(polygon_arbitrary_formation<Unit>::x_))) { + //splice vertical pair into edge above + active_tail_arbitrary* tailabove = (*iter).second; + Point point(polygon_arbitrary_formation<Unit>::x_, + convert_high_precision_type<Unit>((*iter).first.evalAtX(polygon_arbitrary_formation<Unit>::x_))); + verticalPair.second->pushPoint(point); + active_tail_arbitrary::joinChains(point, tailabove, verticalPair.first, true, output); + (*iter).second = verticalPair.second; + verticalPair.first = 0; + verticalPair.second = 0; + } + } + //std::cout << "erasing\n"; + //erase all elements from the tree + for(typename std::vector<iterator>::iterator iter = elementIters.begin(); + iter != elementIters.end(); ++iter) { + //std::cout << "erasing loop\n"; + polygon_arbitrary_formation<Unit>::scanData_.erase(*iter); + } + //switch comparison tie breaking policy + polygon_arbitrary_formation<Unit>::justBefore_ = false; + //add new elements into tree + //std::cout << "inserting\n"; + for(typename std::vector<std::pair<vertex_half_edge, active_tail_arbitrary*> >::iterator iter = elements.begin(); + iter != elements.end(); ++iter) { + //std::cout << "inserting loop\n"; + polygon_arbitrary_formation<Unit>::scanData_.insert(polygon_arbitrary_formation<Unit>::scanData_.end(), *iter); + } + //std::cout << "end processEvent\n"; + return currentIter; + } + public: + template <typename stream_type> + static inline bool testTrapezoidArbitraryFormationRect(stream_type& stdcout) { + stdcout << "testing trapezoid formation\n"; + trapezoid_arbitrary_formation pf; + std::vector<polygon_data<Unit> > polys; + std::vector<vertex_half_edge> data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(10, 10), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(10, 10), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(0, 10), 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing trapezoid formation\n"; + return true; + } + template <typename stream_type> + static inline bool testTrapezoidArbitraryFormationP1(stream_type& stdcout) { + stdcout << "testing trapezoid formation P1\n"; + trapezoid_arbitrary_formation pf; + std::vector<polygon_data<Unit> > polys; + std::vector<vertex_half_edge> data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(10, 20), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(10, 20), -1)); + data.push_back(vertex_half_edge(Point(10, 20), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(10, 20), Point(0, 10), 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing trapezoid formation\n"; + return true; + } + template <typename stream_type> + static inline bool testTrapezoidArbitraryFormationP2(stream_type& stdcout) { + stdcout << "testing trapezoid formation P2\n"; + trapezoid_arbitrary_formation pf; + std::vector<polygon_data<Unit> > polys; + std::vector<vertex_half_edge> data; + data.push_back(vertex_half_edge(Point(-3, 1), Point(2, -4), 1)); + data.push_back(vertex_half_edge(Point(-3, 1), Point(-2, 2), -1)); + data.push_back(vertex_half_edge(Point(-2, 2), Point(2, 4), -1)); + data.push_back(vertex_half_edge(Point(-2, 2), Point(-3, 1), 1)); + data.push_back(vertex_half_edge(Point(2, -4), Point(-3, 1), -1)); + data.push_back(vertex_half_edge(Point(2, -4), Point(2, 4), -1)); + data.push_back(vertex_half_edge(Point(2, 4), Point(-2, 2), 1)); + data.push_back(vertex_half_edge(Point(2, 4), Point(2, -4), 1)); + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing trapezoid formation\n"; + return true; + } + + template <typename stream_type> + static inline bool testTrapezoidArbitraryFormationPolys(stream_type& stdcout) { + stdcout << "testing trapezoid formation polys\n"; + trapezoid_arbitrary_formation pf; + std::vector<polygon_with_holes_data<Unit> > polys; + //trapezoid_arbitrary_formation pf2(true); + //std::vector<polygon_with_holes_data<Unit> > polys2; + std::vector<vertex_half_edge> data; + data.push_back(vertex_half_edge(Point(0, 0), Point(100, 1), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(1, 100), -1)); + data.push_back(vertex_half_edge(Point(1, 100), Point(0, 0), 1)); + data.push_back(vertex_half_edge(Point(1, 100), Point(101, 101), -1)); + data.push_back(vertex_half_edge(Point(100, 1), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(100, 1), Point(101, 101), 1)); + data.push_back(vertex_half_edge(Point(101, 101), Point(100, 1), -1)); + data.push_back(vertex_half_edge(Point(101, 101), Point(1, 100), 1)); + + data.push_back(vertex_half_edge(Point(2, 2), Point(10, 2), -1)); + data.push_back(vertex_half_edge(Point(2, 2), Point(2, 10), -1)); + data.push_back(vertex_half_edge(Point(2, 10), Point(2, 2), 1)); + data.push_back(vertex_half_edge(Point(2, 10), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(10, 2), Point(2, 2), 1)); + data.push_back(vertex_half_edge(Point(10, 2), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(10, 2), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(2, 10), -1)); + + data.push_back(vertex_half_edge(Point(2, 12), Point(10, 12), -1)); + data.push_back(vertex_half_edge(Point(2, 12), Point(2, 22), -1)); + data.push_back(vertex_half_edge(Point(2, 22), Point(2, 12), 1)); + data.push_back(vertex_half_edge(Point(2, 22), Point(10, 22), 1)); + data.push_back(vertex_half_edge(Point(10, 12), Point(2, 12), 1)); + data.push_back(vertex_half_edge(Point(10, 12), Point(10, 22), 1)); + data.push_back(vertex_half_edge(Point(10, 22), Point(10, 12), -1)); + data.push_back(vertex_half_edge(Point(10, 22), Point(2, 22), -1)); + + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + //pf2.scan(polys2, data.begin(), data.end()); + //stdcout << "result size: " << polys2.size() << std::endl; + //for(std::size_t i = 0; i < polys2.size(); ++i) { + // stdcout << polys2[i] << std::endl; + //} + stdcout << "done testing trapezoid formation\n"; + return true; + } + + template <typename stream_type> + static inline bool testTrapezoidArbitraryFormationSelfTouch1(stream_type& stdcout) { + stdcout << "testing trapezoid formation self touch 1\n"; + trapezoid_arbitrary_formation pf; + std::vector<polygon_data<Unit> > polys; + std::vector<vertex_half_edge> data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(5, 10), -1)); + + data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(10, 5), -1)); + + data.push_back(vertex_half_edge(Point(10, 5), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(10, 5), Point(5, 5), 1)); + + data.push_back(vertex_half_edge(Point(5, 10), Point(5, 5), 1)); + data.push_back(vertex_half_edge(Point(5, 10), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(5, 2), Point(5, 5), -1)); + data.push_back(vertex_half_edge(Point(5, 2), Point(7, 2), -1)); + + data.push_back(vertex_half_edge(Point(5, 5), Point(5, 10), -1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(5, 2), 1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); + + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 2), 1)); + + gtlsort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing trapezoid formation\n"; + return true; + } + }; + + template <typename T> + struct PolyLineArbitraryByConcept<T, polygon_with_holes_concept> { typedef poly_line_arbitrary_polygon_data<T> type; }; + template <typename T> + struct PolyLineArbitraryByConcept<T, polygon_concept> { typedef poly_line_arbitrary_hole_data<T> type; }; + + template <typename T> + struct geometry_concept<poly_line_arbitrary_polygon_data<T> > { typedef polygon_45_with_holes_concept type; }; + template <typename T> + struct geometry_concept<poly_line_arbitrary_hole_data<T> > { typedef polygon_45_concept type; }; +} +} +#endif diff --git a/boost/polygon/detail/polygon_formation.hpp b/boost/polygon/detail/polygon_formation.hpp new file mode 100644 index 0000000000..012996271d --- /dev/null +++ b/boost/polygon/detail/polygon_formation.hpp @@ -0,0 +1,1807 @@ +/* + 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_POLYGON_FORMATION_HPP +#define BOOST_POLYGON_POLYGON_FORMATION_HPP +namespace boost { namespace polygon{ + +namespace polygon_formation { + + /* + * End has two states, HEAD and TAIL as is represented by a bool + */ + typedef bool End; + + /* + * HEAD End is represented as false because it is the lesser state + */ + const End HEAD = false; + + /* + * TAIL End is represented by true because TAIL comes after head and 1 after 0 + */ + const End TAIL = true; + + /* + * 2D turning direction, left and right sides (is a boolean value since it has two states.) + */ + typedef bool Side; + + /* + * LEFT Side is 0 because we inuitively think left to right; left < right + */ + const Side LEFT = false; + + /* + * RIGHT Side is 1 so that right > left + */ + const Side RIGHT = true; + + /* + * The PolyLine class is data storage and services for building and representing partial polygons. + * As the polyline is added to it extends its storage to accomodate the data. + * PolyLines can be joined head-to-head/head-to-tail when it is determined that two polylines are + * part of the same polygon. + * PolyLines keep state information about what orientation their incomplete head and tail geometry have, + * which side of the polyline is solid and whether the polyline is joined head-to-head and tail-to-head. + * PolyLines have nothing whatsoever to do with holes. + * It may be valuable to collect a histogram of PolyLine lengths used by an algorithm on its typical data + * sets and tune the allocation of the initial vector of coordinate data to be greater than or equal to + * the mean, median, mode, or mean plus some number of standard deviation, or just generally large enough + * to prevent too much unnecesary reallocations, but not too big that it wastes a lot of memory and degrades cache + * performance. + */ + template <typename Unit> + class PolyLine { + private: + //data + + /* + * ptdata_ a vector of coordiantes + * if VERTICAL_HEAD, first coordiante is an X + * else first coordinate is a Y + */ + std::vector<Unit> ptdata_; + + /* + * head and tail points to other polylines before and after this in a chain + */ + PolyLine* headp_; + PolyLine* tailp_; + + /* + * state bitmask + * bit zero is orientation, 0 H, 1 V + * bit 1 is head connectivity, 0 for head, 1 for tail + * bit 2 is tail connectivity, 0 for head, 1 for tail + * bit 3 is solid to left of PolyLine when 1, right when 0 + */ + int state_; + + public: + /* + * default constructor (for preallocation) + */ + PolyLine(); + + /* + * constructor that takes the orientation, coordiante and side to which there is solid + */ + PolyLine(orientation_2d orient, Unit coord, Side side); + + //copy constructor + PolyLine(const PolyLine& pline); + + //destructor + ~PolyLine(); + + //assignment operator + PolyLine& operator=(const PolyLine& that); + + //equivalence operator + bool operator==(const PolyLine& b) const; + + /* + * valid PolyLine (only default constructed polylines are invalid.) + */ + bool isValid() const; + + /* + * Orientation of Head + */ + orientation_2d headOrient() const; + + /* + * returns true if first coordinate is an X value (first segment is vertical) + */ + bool verticalHead() const; + + /* + * returns the orientation_2d fo the tail + */ + orientation_2d tailOrient() const; + + /* + * returns true if last coordinate is an X value (last segment is vertical) + */ + bool verticalTail() const; + + /* + * retrun true if PolyLine has odd number of coordiantes + */ + bool oddLength() const; + + /* + * retrun the End of the other polyline that the specified end of this polyline is connected to + */ + End endConnectivity(End end) const; + + /* + * retrun true if the head of this polyline is connect to the tail of a polyline + */ + bool headToTail() const; + /* + * retrun true if the head of this polyline is connect to the head of a polyline + */ + bool headToHead() const; + + /* + * retrun true if the tail of this polyline is connect to the tail of a polyline + */ + bool tailToTail() const; + /* + * retrun true if the tail of this polyline is connect to the head of a polyline + */ + bool tailToHead() const; + + /* + * retrun the side on which there is solid for this polyline + */ + Side solidSide() const; + + /* + * retrun true if there is solid to the right of this polyline + */ + bool solidToRight() const; + + /* + * returns true if the polyline tail is not connected + */ + bool active() const; + + /* + * adds a coordinate value to the end of the polyline changing the tail orientation + */ + PolyLine& pushCoordinate(Unit coord); + + /* + * removes a coordinate value at the end of the polyline changing the tail orientation + */ + PolyLine& popCoordinate(); + + /* + * extends the tail of the polyline to include the point, changing orientation if needed + */ + PolyLine& pushPoint(const point_data<Unit>& point); + + /* + * changes the last coordinate of the tail of the polyline by the amount of the delta + */ + PolyLine& extendTail(Unit delta); + + /* + * join thisEnd of this polyline to that polyline's end + */ + PolyLine& joinTo(End thisEnd, PolyLine& that, End end); + + /* + * join an end of this polyline to the tail of that polyline + */ + PolyLine& joinToTail(PolyLine& that, End end); + + /* + * join an end of this polyline to the head of that polyline + */ + PolyLine& joinToHead(PolyLine& that, End end); + + /* + * join the head of this polyline to the head of that polyline + */ + //join this to that in the given way + PolyLine& joinHeadToHead(PolyLine& that); + + /* + * join the head of this polyline to the tail of that polyline + */ + PolyLine& joinHeadToTail(PolyLine& that); + + /* + * join the tail of this polyline to the head of that polyline + */ + PolyLine& joinTailToHead(PolyLine& that); + + /* + * join the tail of this polyline to the tail of that polyline + */ + PolyLine& joinTailToTail(PolyLine& that); + + /* + * dissconnect the tail at the end of the polygon + */ + PolyLine& disconnectTails(); + + /* + * get the coordinate at one end of this polyline, by default the tail end + */ + Unit getEndCoord(End end = TAIL) const; + + /* + * get the point on the polyline at the given index (polylines have the same number of coordinates as points + */ + point_data<Unit> getPoint(unsigned int index) const; + + /* + * get the point on one end of the polyline, by default the tail + */ + point_data<Unit> getEndPoint(End end = TAIL) const; + + /* + * get the orientation of a segment by index + */ + orientation_2d segmentOrient(unsigned int index = 0) const; + + /* + * get a coordinate by index using the square bracket operator + */ + Unit operator[] (unsigned int index) const; + + /* + * get the number of segments/points/coordinates in the polyline + */ + unsigned int numSegments() const; + + /* + * get the pointer to the next polyline at one end of this + */ + PolyLine* next(End end) const; + + /* + * write out coordinates of this and all attached polylines to a single vector + */ + PolyLine* writeOut(std::vector<Unit>& outVec, End startEnd = TAIL) const; + + private: + //methods + PolyLine& joinTo_(End thisEnd, PolyLine& that, End end); + }; + + //forward declaration + template<bool orientT, typename Unit> + class PolyLinePolygonData; + + //forward declaration + template<bool orientT, typename Unit> + class PolyLinePolygonWithHolesData; + + /* + * ActiveTail represents an edge of an incomplete polygon. + * + * An ActiveTail object is the active tail end of a polyline object, which may (should) be the attached to + * a chain of polyline objects through a pointer. The ActiveTail class provides an abstraction between + * and algorithm that builds polygons and the PolyLine data representation of incomplete polygons that are + * being built. It does this by providing an iterface to access the information about the last edge at the + * tail of the PolyLine it is associated with. To a polygon constructing algorithm, an ActiveTail is a floating + * edge of an incomplete polygon and has an orientation and coordinate value, as well as knowing which side of + * that edge is supposed to be solid or space. Any incomplete polygon will have two active tails. Active tails + * may be joined together to merge two incomplete polygons into a larger incomplete polygon. If two active tails + * that are to be merged are the oppositve ends of the same incomplete polygon that indicates that the polygon + * has been closed and is complete. The active tail keeps a pointer to the other active tail of its incomplete + * polygon so that it is easy to check this condition. These pointers are updated when active tails are joined. + * The active tail also keeps a list of pointers to active tail objects that serve as handles to closed holes. In + * this way a hole can be associated to another incomplete polygon, which will eventually be its enclosing shell, + * or reassociate the hole to another incomplete polygon in the case that it become a hole itself. Alternately, + * the active tail may add a filiment to stitch a hole into a shell and "fracture" the hole out of the interior + * of a polygon. The active tail maintains a static output buffer to temporarily write polygon data to when + * it outputs a figure so that outputting a polygon does not require the allocation of a temporary buffer. This + * static buffer should be destroyed whenever the program determines that it won't need it anymore and would prefer to + * release the memory it has allocated back to the system. + */ + template <typename Unit> + class ActiveTail { + private: + //data + PolyLine<Unit>* tailp_; + ActiveTail *otherTailp_; + std::list<ActiveTail*> holesList_; + public: + + /* + * iterator over coordinates of the figure + */ + class iterator { + private: + const PolyLine<Unit>* pLine_; + const PolyLine<Unit>* pLineEnd_; + unsigned int index_; + unsigned int indexEnd_; + End startEnd_; + public: + inline iterator() : pLine_(), pLineEnd_(), index_(), indexEnd_(), startEnd_() {} + inline iterator(const ActiveTail* at, bool isHole, orientation_2d orient) : + pLine_(), pLineEnd_(), index_(), indexEnd_(), startEnd_() { + //if it is a hole and orientation is vertical or it is not a hole and orientation is horizontal + //we want to use this active tail, otherwise we want to use the other active tail + startEnd_ = TAIL; + if(!isHole ^ (orient == HORIZONTAL)) { + //switch winding direction + at = at->getOtherActiveTail(); + } + //now we have the right winding direction + //if it is horizontal we need to skip the first element + pLine_ = at->getTail(); + index_ = at->getTail()->numSegments() - 1; + if((at->getOrient() == HORIZONTAL) ^ (orient == HORIZONTAL)) { + pLineEnd_ = at->getTail(); + indexEnd_ = pLineEnd_->numSegments() - 1; + if(index_ == 0) { + pLine_ = at->getTail()->next(HEAD); + if(at->getTail()->endConnectivity(HEAD) == TAIL) { + index_ = pLine_->numSegments() -1; + } else { + startEnd_ = HEAD; + index_ = 0; + } + } else { --index_; } + } else { + pLineEnd_ = at->getOtherActiveTail()->getTail(); + indexEnd_ = pLineEnd_->numSegments() - 1; + } + at->getTail()->joinTailToTail(*(at->getOtherActiveTail()->getTail())); + } + //use bitwise copy and assign provided by the compiler + inline iterator& operator++() { + if(pLine_ == pLineEnd_ && index_ == indexEnd_) { + pLine_ = 0; + index_ = 0; + return *this; + } + if(startEnd_ == HEAD) { + ++index_; + if(index_ == pLine_->numSegments()) { + End end = pLine_->endConnectivity(TAIL); + pLine_ = pLine_->next(TAIL); + if(end == TAIL) { + startEnd_ = TAIL; + index_ = pLine_->numSegments() -1; + } else { + index_ = 0; + } + } + } else { + if(index_ == 0) { + End end = pLine_->endConnectivity(HEAD); + pLine_ = pLine_->next(HEAD); + if(end == TAIL) { + index_ = pLine_->numSegments() -1; + } else { + startEnd_ = HEAD; + index_ = 0; + } + } else { + --index_; + } + } + return *this; + } + inline const iterator operator++(int) { + iterator tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator& that) const { + return pLine_ == that.pLine_ && index_ == that.index_; + } + inline bool operator!=(const iterator& that) const { + return pLine_ != that.pLine_ || index_ != that.index_; + } + inline Unit operator*() { return (*pLine_)[index_]; } + }; + + /* + * iterator over holes contained within the figure + */ + typedef typename std::list<ActiveTail*>::const_iterator iteratorHoles; + + //default constructor + ActiveTail(); + + //constructor + ActiveTail(orientation_2d orient, Unit coord, Side solidToRight, ActiveTail* otherTailp); + + //constructor + ActiveTail(PolyLine<Unit>* active, ActiveTail* otherTailp); + + //copy constructor + ActiveTail(const ActiveTail& that); + + //destructor + ~ActiveTail(); + + //assignment operator + ActiveTail& operator=(const ActiveTail& that); + + //equivalence operator + bool operator==(const ActiveTail& b) const; + + /* + * comparison operators, ActiveTail objects are sortable by geometry + */ + bool operator<(const ActiveTail& b) const; + bool operator<=(const ActiveTail& b) const; + bool operator>(const ActiveTail& b) const; + bool operator>=(const ActiveTail& b) const; + + /* + * get the pointer to the polyline that this is an active tail of + */ + PolyLine<Unit>* getTail() const; + + /* + * get the pointer to the polyline at the other end of the chain + */ + PolyLine<Unit>* getOtherTail() const; + + /* + * get the pointer to the activetail at the other end of the chain + */ + ActiveTail* getOtherActiveTail() const; + + /* + * test if another active tail is the other end of the chain + */ + bool isOtherTail(const ActiveTail& b); + + /* + * update this end of chain pointer to new polyline + */ + ActiveTail& updateTail(PolyLine<Unit>* newTail); + + /* + * associate a hole to this active tail by the specified policy + */ + ActiveTail* addHole(ActiveTail* hole, bool fractureHoles); + + /* + * get the list of holes + */ + const std::list<ActiveTail*>& getHoles() const; + + /* + * copy holes from that to this + */ + void copyHoles(ActiveTail& that); + + /* + * find out if solid to right + */ + bool solidToRight() const; + + /* + * get coordinate (getCoord and getCoordinate are aliases for eachother) + */ + Unit getCoord() const; + Unit getCoordinate() const; + + /* + * get the tail orientation + */ + orientation_2d getOrient() const; + + /* + * add a coordinate to the polygon at this active tail end, properly handle degenerate edges by removing redundant coordinate + */ + void pushCoordinate(Unit coord); + + /* + * write the figure that this active tail points to out to the temp buffer + */ + void writeOutFigure(std::vector<Unit>& outVec, bool isHole = false) const; + + /* + * write the figure that this active tail points to out through iterators + */ + void writeOutFigureItrs(iterator& beginOut, iterator& endOut, bool isHole = false, orientation_2d orient = VERTICAL) const; + iterator begin(bool isHole, orientation_2d orient) const; + iterator end() const; + + /* + * write the holes that this active tail points to out through iterators + */ + void writeOutFigureHoleItrs(iteratorHoles& beginOut, iteratorHoles& endOut) const; + iteratorHoles beginHoles() const; + iteratorHoles endHoles() const; + + /* + * joins the two chains that the two active tail tails are ends of + * checks for closure of figure and writes out polygons appropriately + * returns a handle to a hole if one is closed + */ + static ActiveTail* joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, std::vector<Unit>& outBufferTmp); + template <typename PolygonT> + static ActiveTail* joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, typename std::vector<PolygonT>& outBufferTmp); + + /* + * deallocate temp buffer + */ + static void destroyOutBuffer(); + + /* + * deallocate all polygon data this active tail points to (deep delete, call only from one of a pair of active tails) + */ + void destroyContents(); + }; + + /* allocate a polyline object */ + template <typename Unit> + PolyLine<Unit>* createPolyLine(orientation_2d orient, Unit coord, Side side); + + /* deallocate a polyline object */ + template <typename Unit> + void destroyPolyLine(PolyLine<Unit>* pLine); + + /* allocate an activetail object */ + template <typename Unit> + ActiveTail<Unit>* createActiveTail(); + + /* deallocate an activetail object */ + template <typename Unit> + void destroyActiveTail(ActiveTail<Unit>* aTail); + + template<bool orientT, typename Unit> + class PolyLineHoleData { + private: + ActiveTail<Unit>* p_; + public: + typedef Unit coordinate_type; + typedef typename ActiveTail<Unit>::iterator compact_iterator_type; + typedef iterator_compact_to_points<compact_iterator_type, point_data<coordinate_type> > iterator_type; + inline PolyLineHoleData() : p_(0) {} + inline PolyLineHoleData(ActiveTail<Unit>* p) : p_(p) {} + //use default copy and assign + inline compact_iterator_type begin_compact() const { return p_->begin(true, (orientT ? VERTICAL : HORIZONTAL)); } + inline compact_iterator_type end_compact() const { return p_->end(); } + inline iterator_type begin() const { return iterator_type(begin_compact(), end_compact()); } + inline iterator_type end() const { return iterator_type(end_compact(), end_compact()); } + inline std::size_t size() const { return 0; } + inline ActiveTail<Unit>* yield() { return p_; } + template<class iT> + inline PolyLineHoleData& set(iT inputBegin, iT inputEnd) { + return *this; + } + template<class iT> + inline PolyLineHoleData& set_compact(iT inputBegin, iT inputEnd) { + return *this; + } + + }; + + template<bool orientT, typename Unit> + class PolyLinePolygonWithHolesData { + private: + ActiveTail<Unit>* p_; + public: + typedef Unit coordinate_type; + typedef typename ActiveTail<Unit>::iterator compact_iterator_type; + typedef iterator_compact_to_points<compact_iterator_type, point_data<coordinate_type> > iterator_type; + typedef PolyLineHoleData<orientT, Unit> hole_type; + typedef typename coordinate_traits<Unit>::area_type area_type; + class iteratorHoles { + private: + typename ActiveTail<Unit>::iteratorHoles itr_; + public: + inline iteratorHoles() : itr_() {} + inline iteratorHoles(typename ActiveTail<Unit>::iteratorHoles itr) : itr_(itr) {} + //use bitwise copy and assign provided by the compiler + inline iteratorHoles& operator++() { + ++itr_; + return *this; + } + inline const iteratorHoles operator++(int) { + iteratorHoles tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iteratorHoles& that) const { + return itr_ == that.itr_; + } + inline bool operator!=(const iteratorHoles& that) const { + return itr_ != that.itr_; + } + inline PolyLineHoleData<orientT, Unit> operator*() { return PolyLineHoleData<orientT, Unit>(*itr_);} + }; + typedef iteratorHoles iterator_holes_type; + + inline PolyLinePolygonWithHolesData() : p_(0) {} + inline PolyLinePolygonWithHolesData(ActiveTail<Unit>* p) : p_(p) {} + //use default copy and assign + inline compact_iterator_type begin_compact() const { return p_->begin(false, (orientT ? VERTICAL : HORIZONTAL)); } + inline compact_iterator_type end_compact() const { return p_->end(); } + inline iterator_type begin() const { return iterator_type(begin_compact(), end_compact()); } + inline iterator_type end() const { return iterator_type(end_compact(), end_compact()); } + inline iteratorHoles begin_holes() const { return iteratorHoles(p_->beginHoles()); } + inline iteratorHoles end_holes() const { return iteratorHoles(p_->endHoles()); } + inline ActiveTail<Unit>* yield() { return p_; } + //stub out these four required functions that will not be used but are needed for the interface + inline std::size_t size_holes() const { return 0; } + inline std::size_t size() const { return 0; } + template<class iT> + inline PolyLinePolygonWithHolesData& set(iT inputBegin, iT inputEnd) { + return *this; + } + template<class iT> + inline PolyLinePolygonWithHolesData& set_compact(iT inputBegin, iT inputEnd) { + return *this; + } + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template<class iT> + inline PolyLinePolygonWithHolesData& set_holes(iT inputBegin, iT inputEnd) { + return *this; + } + }; + + + template <bool orientT, typename Unit, typename polygon_concept_type> + struct PolyLineType { }; + template <bool orientT, typename Unit> + struct PolyLineType<orientT, Unit, polygon_90_with_holes_concept> { typedef PolyLinePolygonWithHolesData<orientT, Unit> type; }; + template <bool orientT, typename Unit> + struct PolyLineType<orientT, Unit, polygon_45_with_holes_concept> { typedef PolyLinePolygonWithHolesData<orientT, Unit> type; }; + template <bool orientT, typename Unit> + struct PolyLineType<orientT, Unit, polygon_with_holes_concept> { typedef PolyLinePolygonWithHolesData<orientT, Unit> type; }; + template <bool orientT, typename Unit> + struct PolyLineType<orientT, Unit, polygon_90_concept> { typedef PolyLineHoleData<orientT, Unit> type; }; + template <bool orientT, typename Unit> + struct PolyLineType<orientT, Unit, polygon_45_concept> { typedef PolyLineHoleData<orientT, Unit> type; }; + template <bool orientT, typename Unit> + struct PolyLineType<orientT, Unit, polygon_concept> { typedef PolyLineHoleData<orientT, Unit> type; }; + + template <bool orientT, typename Unit, typename polygon_concept_type> + class ScanLineToPolygonItrs { + private: + std::map<Unit, ActiveTail<Unit>*> tailMap_; + typedef typename PolyLineType<orientT, Unit, polygon_concept_type>::type PolyLinePolygonData; + std::vector<PolyLinePolygonData> outputPolygons_; + bool fractureHoles_; + public: + typedef typename std::vector<PolyLinePolygonData>::iterator iterator; + inline ScanLineToPolygonItrs() : tailMap_(), outputPolygons_(), fractureHoles_(false) {} + /* construct a scanline with the proper offsets, protocol and options */ + inline ScanLineToPolygonItrs(bool fractureHoles) : tailMap_(), outputPolygons_(), fractureHoles_(fractureHoles) {} + + ~ScanLineToPolygonItrs() { clearOutput_(); } + + /* process all vertical edges, left and right, at a unique x coordinate, edges must be sorted low to high */ + void processEdges(iterator& beginOutput, iterator& endOutput, + Unit currentX, std::vector<interval_data<Unit> >& leftEdges, + std::vector<interval_data<Unit> >& rightEdges); + + private: + void clearOutput_(); + }; + + /* + * ScanLine does all the work of stitching together polygons from incoming vertical edges + */ +// template <typename Unit, typename polygon_concept_type> +// class ScanLineToPolygons { +// private: +// ScanLineToPolygonItrs<true, Unit> scanline_; +// public: +// inline ScanLineToPolygons() : scanline_() {} +// /* construct a scanline with the proper offsets, protocol and options */ +// inline ScanLineToPolygons(bool fractureHoles) : scanline_(fractureHoles) {} + +// /* process all vertical edges, left and right, at a unique x coordinate, edges must be sorted low to high */ +// inline void processEdges(std::vector<Unit>& outBufferTmp, Unit currentX, std::vector<interval_data<Unit> >& leftEdges, +// std::vector<interval_data<Unit> >& rightEdges) { +// typename ScanLineToPolygonItrs<true, Unit>::iterator itr, endItr; +// scanline_.processEdges(itr, endItr, currentX, leftEdges, rightEdges); +// //copy data into outBufferTmp +// while(itr != endItr) { +// typename PolyLinePolygonData<true, Unit>::iterator pditr; +// outBufferTmp.push_back(0); +// unsigned int sizeIndex = outBufferTmp.size() - 1; +// int count = 0; +// for(pditr = (*itr).begin(); pditr != (*itr).end(); ++pditr) { +// outBufferTmp.push_back(*pditr); +// ++count; +// } +// outBufferTmp[sizeIndex] = count; +// typename PolyLinePolygonData<true, Unit>::iteratorHoles pdHoleItr; +// for(pdHoleItr = (*itr).beginHoles(); pdHoleItr != (*itr).endHoles(); ++pdHoleItr) { +// outBufferTmp.push_back(0); +// unsigned int sizeIndex2 = outBufferTmp.size() - 1; +// int count2 = 0; +// for(pditr = (*pdHoleItr).begin(); pditr != (*pdHoleItr).end(); ++pditr) { +// outBufferTmp.push_back(*pditr); +// ++count2; +// } +// outBufferTmp[sizeIndex2] = -count; +// } +// ++itr; +// } +// } +// }; + + const int VERTICAL_HEAD = 1, HEAD_TO_TAIL = 2, TAIL_TO_TAIL = 4, SOLID_TO_RIGHT = 8; + + //EVERY FUNCTION in this DEF file should be explicitly defined as inline + + //microsoft compiler improperly warns whenever you cast an integer to bool + //call this function on an integer to convert it to bool without a warning + template <class T> + inline bool to_bool(const T& val) { return val != 0; } + + //default constructor (for preallocation) + template <typename Unit> + inline PolyLine<Unit>::PolyLine() : ptdata_() ,headp_(0), tailp_(0), state_(-1) {} + + //constructor + template <typename Unit> + inline PolyLine<Unit>::PolyLine(orientation_2d orient, Unit coord, Side side) : + ptdata_(1, coord), + headp_(0), + tailp_(0), + state_(orient.to_int() + + (side << 3)) {} + + //copy constructor + template <typename Unit> + inline PolyLine<Unit>::PolyLine(const PolyLine<Unit>& pline) : ptdata_(pline.ptdata_), + headp_(pline.headp_), + tailp_(pline.tailp_), + state_(pline.state_) {} + + //destructor + template <typename Unit> + inline PolyLine<Unit>::~PolyLine() { + //clear out data just in case it is read later + headp_ = tailp_ = 0; + state_ = 0; + } + + template <typename Unit> + inline PolyLine<Unit>& PolyLine<Unit>::operator=(const PolyLine<Unit>& that) { + if(!(this == &that)) { + headp_ = that.headp_; + tailp_ = that.tailp_; + ptdata_ = that.ptdata_; + state_ = that.state_; + } + return *this; + } + + template <typename Unit> + inline bool PolyLine<Unit>::operator==(const PolyLine<Unit>& b) const { + return this == &b || (state_ == b.state_ && + headp_ == b.headp_ && + tailp_ == b.tailp_); + } + + //valid PolyLine + template <typename Unit> + inline bool PolyLine<Unit>::isValid() const { + return state_ > -1; } + + //first coordinate is an X value + //first segment is vertical + template <typename Unit> + inline bool PolyLine<Unit>::verticalHead() const { + return state_ & VERTICAL_HEAD; + } + + //retrun true is PolyLine has odd number of coordiantes + template <typename Unit> + inline bool PolyLine<Unit>::oddLength() const { + return to_bool((ptdata_.size()-1) % 2); + } + + //last coordiante is an X value + //last segment is vertical + template <typename Unit> + inline bool PolyLine<Unit>::verticalTail() const { + return to_bool(verticalHead() ^ oddLength()); + } + + template <typename Unit> + inline orientation_2d PolyLine<Unit>::tailOrient() const { + return (verticalTail() ? VERTICAL : HORIZONTAL); + } + + template <typename Unit> + inline orientation_2d PolyLine<Unit>::headOrient() const { + return (verticalHead() ? VERTICAL : HORIZONTAL); + } + + template <typename Unit> + inline End PolyLine<Unit>::endConnectivity(End end) const { + //Tail should be defined as true + if(end) { return tailToTail(); } + return headToTail(); + } + + template <typename Unit> + inline bool PolyLine<Unit>::headToTail() const { + return to_bool(state_ & HEAD_TO_TAIL); + } + + template <typename Unit> + inline bool PolyLine<Unit>::headToHead() const { + return to_bool(!headToTail()); + } + + template <typename Unit> + inline bool PolyLine<Unit>::tailToHead() const { + return to_bool(!tailToTail()); + } + + template <typename Unit> + inline bool PolyLine<Unit>::tailToTail() const { + return to_bool(state_ & TAIL_TO_TAIL); + } + + template <typename Unit> + inline Side PolyLine<Unit>::solidSide() const { + return solidToRight(); } + + template <typename Unit> + inline bool PolyLine<Unit>::solidToRight() const { + return to_bool(state_ & SOLID_TO_RIGHT) != 0; + } + + template <typename Unit> + inline bool PolyLine<Unit>::active() const { + return !to_bool(tailp_); + } + + template <typename Unit> + inline PolyLine<Unit>& PolyLine<Unit>::pushCoordinate(Unit coord) { + ptdata_.push_back(coord); + return *this; + } + + template <typename Unit> + inline PolyLine<Unit>& PolyLine<Unit>::popCoordinate() { + ptdata_.pop_back(); + return *this; + } + + template <typename Unit> + inline PolyLine<Unit>& PolyLine<Unit>::pushPoint(const point_data<Unit>& point) { + point_data<Unit> endPt = getEndPoint(); + //vertical is true, horizontal is false + if((tailOrient().to_int() ? point.get(VERTICAL) == endPt.get(VERTICAL) : point.get(HORIZONTAL) == endPt.get(HORIZONTAL))) { + //we were pushing a colinear segment + return popCoordinate(); + } + return pushCoordinate(tailOrient().to_int() ? point.get(VERTICAL) : point.get(HORIZONTAL)); + } + + template <typename Unit> + inline PolyLine<Unit>& PolyLine<Unit>::extendTail(Unit delta) { + ptdata_.back() += delta; + return *this; + } + + //private member function that creates a link from this PolyLine to that + template <typename Unit> + inline PolyLine<Unit>& PolyLine<Unit>::joinTo_(End thisEnd, PolyLine<Unit>& that, End end) { + if(thisEnd){ + tailp_ = &that; + state_ &= ~TAIL_TO_TAIL; //clear any previous state_ of bit (for safety) + state_ |= (end << 2); //place bit into mask + } else { + headp_ = &that; + state_ &= ~HEAD_TO_TAIL; //clear any previous state_ of bit (for safety) + state_ |= (end << 1); //place bit into mask + } + return *this; + } + + //join two PolyLines (both ways of the association) + template <typename Unit> + inline PolyLine<Unit>& PolyLine<Unit>::joinTo(End thisEnd, PolyLine<Unit>& that, End end) { + joinTo_(thisEnd, that, end); + that.joinTo_(end, *this, thisEnd); + return *this; + } + + //convenience functions for joining PolyLines + template <typename Unit> + inline PolyLine<Unit>& PolyLine<Unit>::joinToTail(PolyLine<Unit>& that, End end) { + return joinTo(TAIL, that, end); + } + template <typename Unit> + inline PolyLine<Unit>& PolyLine<Unit>::joinToHead(PolyLine<Unit>& that, End end) { + return joinTo(HEAD, that, end); + } + template <typename Unit> + inline PolyLine<Unit>& PolyLine<Unit>::joinHeadToHead(PolyLine<Unit>& that) { + return joinToHead(that, HEAD); + } + template <typename Unit> + inline PolyLine<Unit>& PolyLine<Unit>::joinHeadToTail(PolyLine<Unit>& that) { + return joinToHead(that, TAIL); + } + template <typename Unit> + inline PolyLine<Unit>& PolyLine<Unit>::joinTailToHead(PolyLine<Unit>& that) { + return joinToTail(that, HEAD); + } + template <typename Unit> + inline PolyLine<Unit>& PolyLine<Unit>::joinTailToTail(PolyLine<Unit>& that) { + return joinToTail(that, TAIL); + } + + template <typename Unit> + inline PolyLine<Unit>& PolyLine<Unit>::disconnectTails() { + next(TAIL)->state_ &= !TAIL_TO_TAIL; + next(TAIL)->tailp_ = 0; + state_ &= !TAIL_TO_TAIL; + tailp_ = 0; + return *this; + } + + template <typename Unit> + inline Unit PolyLine<Unit>::getEndCoord(End end) const { + if(end) + return ptdata_.back(); + return ptdata_.front(); + } + + template <typename Unit> + inline orientation_2d PolyLine<Unit>::segmentOrient(unsigned int index) const { + return (to_bool((unsigned int)verticalHead() ^ (index % 2)) ? VERTICAL : HORIZONTAL); + } + + template <typename Unit> + inline point_data<Unit> PolyLine<Unit>::getPoint(unsigned int index) const { + //assert(isValid() && headp_->isValid()) ("PolyLine: headp_ must be valid"); + point_data<Unit> pt; + pt.set(HORIZONTAL, ptdata_[index]); + pt.set(VERTICAL, ptdata_[index]); + Unit prevCoord; + if(index == 0) { + prevCoord = headp_->getEndCoord(headToTail()); + } else { + prevCoord = ptdata_[index-1]; + } + pt.set(segmentOrient(index), prevCoord); + return pt; + } + + template <typename Unit> + inline point_data<Unit> PolyLine<Unit>::getEndPoint(End end) const { + return getPoint((end ? numSegments() - 1 : (unsigned int)0)); + } + + template <typename Unit> + inline Unit PolyLine<Unit>::operator[] (unsigned int index) const { + //assert(ptdata_.size() > index) ("PolyLine: out of bounds index"); + return ptdata_[index]; + } + + template <typename Unit> + inline unsigned int PolyLine<Unit>::numSegments() const { + return ptdata_.size(); + } + + template <typename Unit> + inline PolyLine<Unit>* PolyLine<Unit>::next(End end) const { + return (end ? tailp_ : headp_); + } + + template <typename Unit> + inline ActiveTail<Unit>::ActiveTail() : tailp_(0), otherTailp_(0), holesList_() {} + + template <typename Unit> + inline ActiveTail<Unit>::ActiveTail(orientation_2d orient, Unit coord, Side solidToRight, ActiveTail* otherTailp) : + tailp_(0), otherTailp_(0), holesList_() { + tailp_ = createPolyLine(orient, coord, solidToRight); + otherTailp_ = otherTailp; + } + + template <typename Unit> + inline ActiveTail<Unit>::ActiveTail(PolyLine<Unit>* active, ActiveTail<Unit>* otherTailp) : + tailp_(active), otherTailp_(otherTailp), holesList_() {} + + //copy constructor + template <typename Unit> + inline ActiveTail<Unit>::ActiveTail(const ActiveTail<Unit>& that) : tailp_(that.tailp_), otherTailp_(that.otherTailp_), holesList_() {} + + //destructor + template <typename Unit> + inline ActiveTail<Unit>::~ActiveTail() { + //clear them in case the memory is read later + tailp_ = 0; otherTailp_ = 0; + } + + template <typename Unit> + inline ActiveTail<Unit>& ActiveTail<Unit>::operator=(const ActiveTail<Unit>& that) { + //self assignment is safe in this case + tailp_ = that.tailp_; + otherTailp_ = that.otherTailp_; + return *this; + } + + template <typename Unit> + inline bool ActiveTail<Unit>::operator==(const ActiveTail<Unit>& b) const { + return tailp_ == b.tailp_ && otherTailp_ == b.otherTailp_; + } + + template <typename Unit> + inline bool ActiveTail<Unit>::operator<(const ActiveTail<Unit>& b) const { + return tailp_->getEndPoint().get(VERTICAL) < b.tailp_->getEndPoint().get(VERTICAL); + } + + template <typename Unit> + inline bool ActiveTail<Unit>::operator<=(const ActiveTail<Unit>& b) const { + return !(*this > b); } + + template <typename Unit> + inline bool ActiveTail<Unit>::operator>(const ActiveTail<Unit>& b) const { + return b < (*this); } + + template <typename Unit> + inline bool ActiveTail<Unit>::operator>=(const ActiveTail<Unit>& b) const { + return !(*this < b); } + + template <typename Unit> + inline PolyLine<Unit>* ActiveTail<Unit>::getTail() const { + return tailp_; } + + template <typename Unit> + inline PolyLine<Unit>* ActiveTail<Unit>::getOtherTail() const { + return otherTailp_->tailp_; } + + template <typename Unit> + inline ActiveTail<Unit>* ActiveTail<Unit>::getOtherActiveTail() const { + return otherTailp_; } + + template <typename Unit> + inline bool ActiveTail<Unit>::isOtherTail(const ActiveTail<Unit>& b) { + // assert( (tailp_ == b.getOtherTail() && getOtherTail() == b.tailp_) || + // (tailp_ != b.getOtherTail() && getOtherTail() != b.tailp_)) + // ("ActiveTail: Active tails out of sync"); + return otherTailp_ == &b; + } + + template <typename Unit> + inline ActiveTail<Unit>& ActiveTail<Unit>::updateTail(PolyLine<Unit>* newTail) { + tailp_ = newTail; + return *this; + } + + template <typename Unit> + inline ActiveTail<Unit>* ActiveTail<Unit>::addHole(ActiveTail<Unit>* hole, bool fractureHoles) { + if(!fractureHoles){ + holesList_.push_back(hole); + copyHoles(*hole); + copyHoles(*(hole->getOtherActiveTail())); + return this; + } + ActiveTail<Unit>* h, *v; + ActiveTail<Unit>* other = hole->getOtherActiveTail(); + if(other->getOrient() == VERTICAL) { + //assert that hole.getOrient() == HORIZONTAL + //this case should never happen + h = hole; + v = other; + } else { + //assert that hole.getOrient() == VERTICAL + h = other; + v = hole; + } + h->pushCoordinate(v->getCoordinate()); + //assert that h->getOrient() == VERTICAL + //v->pushCoordinate(getCoordinate()); + //assert that v->getOrient() == VERTICAL + //I can't close a figure by adding a hole, so pass zero for xMin and yMin + std::vector<Unit> tmpVec; + ActiveTail<Unit>::joinChains(this, h, false, tmpVec); + return v; + } + + template <typename Unit> + inline const std::list<ActiveTail<Unit>*>& ActiveTail<Unit>::getHoles() const { + return holesList_; + } + + template <typename Unit> + inline void ActiveTail<Unit>::copyHoles(ActiveTail<Unit>& that) { + holesList_.splice(holesList_.end(), that.holesList_); //splice the two lists together + } + + template <typename Unit> + inline bool ActiveTail<Unit>::solidToRight() const { + return getTail()->solidToRight(); } + + template <typename Unit> + inline Unit ActiveTail<Unit>::getCoord() const { + return getTail()->getEndCoord(); } + + template <typename Unit> + inline Unit ActiveTail<Unit>::getCoordinate() const { + return getCoord(); } + + template <typename Unit> + inline orientation_2d ActiveTail<Unit>::getOrient() const { + return getTail()->tailOrient(); } + + template <typename Unit> + inline void ActiveTail<Unit>::pushCoordinate(Unit coord) { + //appropriately handle any co-linear polyline segments by calling push point internally + point_data<Unit> p; + p.set(HORIZONTAL, coord); + p.set(VERTICAL, coord); + //if we are vertical assign the last coordinate (an X) to p.x, else to p.y + p.set(getOrient().get_perpendicular(), getCoordinate()); + tailp_->pushPoint(p); + } + + + //global utility functions + template <typename Unit> + inline PolyLine<Unit>* createPolyLine(orientation_2d orient, Unit coord, Side side) { + return new PolyLine<Unit>(orient, coord, side); + } + + template <typename Unit> + inline void destroyPolyLine(PolyLine<Unit>* pLine) { + delete pLine; + } + + template <typename Unit> + inline ActiveTail<Unit>* createActiveTail() { + //consider replacing system allocator with ActiveTail memory pool + return new ActiveTail<Unit>(); + } + + template <typename Unit> + inline void destroyActiveTail(ActiveTail<Unit>* aTail) { + delete aTail; + } + + + //no recursion, to prevent max recursion depth errors + template <typename Unit> + inline void ActiveTail<Unit>::destroyContents() { + tailp_->disconnectTails(); + PolyLine<Unit>* nextPolyLinep = tailp_->next(HEAD); + End end = tailp_->endConnectivity(HEAD); + destroyPolyLine(tailp_); + while(nextPolyLinep) { + End nextEnd = nextPolyLinep->endConnectivity(!end); //get the direction of next polyLine + PolyLine<Unit>* nextNextPolyLinep = nextPolyLinep->next(!end); //get the next polyline + destroyPolyLine(nextPolyLinep); //destroy the current polyline + end = nextEnd; + nextPolyLinep = nextNextPolyLinep; + } + } + + template <typename Unit> + inline typename ActiveTail<Unit>::iterator ActiveTail<Unit>::begin(bool isHole, orientation_2d orient) const { + return iterator(this, isHole, orient); + } + + template <typename Unit> + inline typename ActiveTail<Unit>::iterator ActiveTail<Unit>::end() const { + return iterator(); + } + + template <typename Unit> + inline typename ActiveTail<Unit>::iteratorHoles ActiveTail<Unit>::beginHoles() const { + return holesList_.begin(); + } + + template <typename Unit> + inline typename ActiveTail<Unit>::iteratorHoles ActiveTail<Unit>::endHoles() const { + return holesList_.end(); + } + + template <typename Unit> + inline void ActiveTail<Unit>::writeOutFigureItrs(iterator& beginOut, iterator& endOut, bool isHole, orientation_2d orient) const { + beginOut = begin(isHole, orient); + endOut = end(); + } + + template <typename Unit> + inline void ActiveTail<Unit>::writeOutFigureHoleItrs(iteratorHoles& beginOut, iteratorHoles& endOut) const { + beginOut = beginHoles(); + endOut = endHoles(); + } + + template <typename Unit> + inline void ActiveTail<Unit>::writeOutFigure(std::vector<Unit>& outVec, bool isHole) const { + //we start writing out the polyLine that this active tail points to at its tail + std::size_t size = outVec.size(); + outVec.push_back(0); //place holder for size + PolyLine<Unit>* nextPolyLinep = 0; + if(!isHole){ + nextPolyLinep = otherTailp_->tailp_->writeOut(outVec); + } else { + nextPolyLinep = tailp_->writeOut(outVec); + } + Unit firsty = outVec[size + 1]; + if((getOrient() == HORIZONTAL) ^ !isHole) { + //our first coordinate is a y value, so we need to rotate it to the end + typename std::vector<Unit>::iterator tmpItr = outVec.begin(); + tmpItr += size; + outVec.erase(++tmpItr); //erase the 2nd element + } + End startEnd = tailp_->endConnectivity(HEAD); + if(isHole) startEnd = otherTailp_->tailp_->endConnectivity(HEAD); + while(nextPolyLinep) { + bool nextStartEnd = nextPolyLinep->endConnectivity(!startEnd); + nextPolyLinep = nextPolyLinep->writeOut(outVec, startEnd); + startEnd = nextStartEnd; + } + if((getOrient() == HORIZONTAL) ^ !isHole) { + //we want to push the y value onto the end since we ought to have ended with an x + outVec.push_back(firsty); //should never be executed because we want first value to be an x + } + //the vector contains the coordinates of the linked list of PolyLines in the correct order + //first element is supposed to be the size + outVec[size] = outVec.size() - 1 - size; //number of coordinates in vector + //assert outVec[size] % 2 == 0 //it should be even + //make the size negative for holes + outVec[size] *= (isHole ? -1 : 1); + } + + //no recursion to prevent max recursion depth errors + template <typename Unit> + inline PolyLine<Unit>* PolyLine<Unit>::writeOut(std::vector<Unit>& outVec, End startEnd) const { + if(startEnd == HEAD){ + //forward order + outVec.insert(outVec.end(), ptdata_.begin(), ptdata_.end()); + return tailp_; + }else{ + //reverse order + //do not reserve because we expect outVec to be large enough already + for(int i = ptdata_.size() - 1; i >= 0; --i){ + outVec.push_back(ptdata_[i]); + } + //NT didn't know about this version of the API.... + //outVec.insert(outVec.end(), ptdata_.rbegin(), ptdata_.rend()); + return headp_; + } + } + + //solid indicates if it was joined by a solit or a space + template <typename Unit> + inline ActiveTail<Unit>* ActiveTail<Unit>::joinChains(ActiveTail<Unit>* at1, ActiveTail<Unit>* at2, bool solid, std::vector<Unit>& outBufferTmp) + { + //checks to see if we closed a figure + if(at1->isOtherTail(*at2)){ + //value of solid tells us if we closed solid or hole + //and output the solid or handle the hole appropriately + //if the hole needs to fracture across horizontal partition boundary we need to notify + //the calling context to do so + if(solid) { + //the chains are being joined because there is solid to the right + //this means that if the figure is closed at this point it must be a hole + //because otherwise it would have to have another vertex to the right of this one + //and would not be closed at this point + return at1; + } else { + //assert pG != 0 + //the figure that was closed is a shell + at1->writeOutFigure(outBufferTmp); + //process holes of the polygon + at1->copyHoles(*at2); //there should not be holes on at2, but if there are, copy them over + const std::list<ActiveTail<Unit>*>& holes = at1->getHoles(); + for(typename std::list<ActiveTail<Unit>*>::const_iterator litr = holes.begin(); litr != holes.end(); ++litr) { + (*litr)->writeOutFigure(outBufferTmp, true); + //delete the hole + (*litr)->destroyContents(); + destroyActiveTail((*litr)->getOtherActiveTail()); + destroyActiveTail((*litr)); + } + //delete the polygon + at1->destroyContents(); + //at2 contents are the same as at1, so it should not destroy them + destroyActiveTail(at1); + destroyActiveTail(at2); + } + return 0; + } + //join the two partial polygons into one large partial polygon + at1->getTail()->joinTailToTail(*(at2->getTail())); + *(at1->getOtherActiveTail()) = ActiveTail(at1->getOtherTail(), at2->getOtherActiveTail()); + *(at2->getOtherActiveTail()) = ActiveTail(at2->getOtherTail(), at1->getOtherActiveTail()); + at1->getOtherActiveTail()->copyHoles(*at1); + at1->getOtherActiveTail()->copyHoles(*at2); + destroyActiveTail(at1); + destroyActiveTail(at2); + return 0; + } + + //solid indicates if it was joined by a solit or a space + template <typename Unit> + template <typename PolygonT> + inline ActiveTail<Unit>* ActiveTail<Unit>::joinChains(ActiveTail<Unit>* at1, ActiveTail<Unit>* at2, bool solid, + std::vector<PolygonT>& outBufferTmp) { + //checks to see if we closed a figure + if(at1->isOtherTail(*at2)){ + //value of solid tells us if we closed solid or hole + //and output the solid or handle the hole appropriately + //if the hole needs to fracture across horizontal partition boundary we need to notify + //the calling context to do so + if(solid) { + //the chains are being joined because there is solid to the right + //this means that if the figure is closed at this point it must be a hole + //because otherwise it would have to have another vertex to the right of this one + //and would not be closed at this point + return at1; + } else { + //assert pG != 0 + //the figure that was closed is a shell + outBufferTmp.push_back(at1); + at1->copyHoles(*at2); //there should not be holes on at2, but if there are, copy them over + } + return 0; + } + //join the two partial polygons into one large partial polygon + at1->getTail()->joinTailToTail(*(at2->getTail())); + *(at1->getOtherActiveTail()) = ActiveTail<Unit>(at1->getOtherTail(), at2->getOtherActiveTail()); + *(at2->getOtherActiveTail()) = ActiveTail<Unit>(at2->getOtherTail(), at1->getOtherActiveTail()); + at1->getOtherActiveTail()->copyHoles(*at1); + at1->getOtherActiveTail()->copyHoles(*at2); + destroyActiveTail(at1); + destroyActiveTail(at2); + return 0; + } + + template <class TKey, class T> inline typename std::map<TKey, T>::iterator findAtNext(std::map<TKey, T>& theMap, + typename std::map<TKey, T>::iterator pos, const TKey& key) + { + if(pos == theMap.end()) return theMap.find(key); + //if they match the mapItr is pointing to the correct position + if(pos->first < key) { + return theMap.find(key); + } + if(pos->first > key) { + return theMap.end(); + } + //else they are equal and no need to do anything to the iterator + return pos; + } + + // createActiveTailsAsPair is called in these two end cases of geometry + // 1. lower left concave corner + // ###| + // ###| + // ###|### + // ###|### + // 2. lower left convex corner + // |### + // |### + // | + // | + // In case 1 there may be a hole propigated up from the bottom. If the fracture option is enabled + // the two active tails that form the filament fracture line edges can become the new active tail pair + // by pushing x and y onto them. Otherwise the hole simply needs to be associated to one of the new active tails + // with add hole + template <typename Unit> + inline std::pair<ActiveTail<Unit>*, ActiveTail<Unit>*> createActiveTailsAsPair(Unit x, Unit y, bool solid, ActiveTail<Unit>* phole, bool fractureHoles) { + ActiveTail<Unit>* at1 = 0; + ActiveTail<Unit>* at2 = 0; + if(!phole || !fractureHoles){ + at1 = createActiveTail<Unit>(); + at2 = createActiveTail<Unit>(); + (*at1) = ActiveTail<Unit>(VERTICAL, x, solid, at2); + (*at2) = ActiveTail<Unit>(HORIZONTAL, y, !solid, at1); + //provide a function through activeTail class to provide this + at1->getTail()->joinHeadToHead(*(at2->getTail())); + if(phole) + at1->addHole(phole, fractureHoles); //assert fractureHoles == false + return std::pair<ActiveTail<Unit>*, ActiveTail<Unit>*>(at1, at2); + } + //assert phole is not null + //assert fractureHoles is true + if(phole->getOrient() == VERTICAL) { + at2 = phole; + } else { + at2 = phole->getOtherActiveTail(); //should never be executed since orientation is expected to be vertical + } + //assert solid == false, we should be creating a corner with solid below and to the left if there was a hole + at1 = at2->getOtherActiveTail(); + //assert at1 is horizontal + at1->pushCoordinate(x); + //assert at2 is vertical + at2->pushCoordinate(y); + return std::pair<ActiveTail<Unit>*, ActiveTail<Unit>*>(at1, at2); + } + + //Process edges connects vertical input edges (right or left edges of figures) to horizontal edges stored as member + //data of the scanline object. It also creates now horizontal edges as needed to construct figures from edge data. + // + //There are only 12 geometric end cases where the scanline intersects a horizontal edge and even fewer unique + //actions to take: + // 1. Solid on both sides of the vertical partition after the current position and space on both sides before + // ###|### + // ###|### + // | + // | + // This case does not need to be handled because there is no vertical edge at the current x coordinate. + // + // 2. Solid on both sides of the vertical partition before the current position and space on both sides after + // | + // | + // ###|### + // ###|### + // This case does not need to be handled because there is no vertical edge at the current x coordinate. + // + // 3. Solid on the left of the vertical partition after the current position and space elsewhere + // ###| + // ###| + // | + // | + // The horizontal edge from the left is found and turns upward because of the vertical right edge to become + // the currently active vertical edge. + // + // 4. Solid on the left of the vertical partion before the current position and space elsewhere + // | + // | + // ###| + // ###| + // The horizontal edge from the left is found and joined to the currently active vertical edge. + // + // 5. Solid to the right above and below and solid to the left above current position. + // ###|### + // ###|### + // |### + // |### + // The horizontal edge from the left is found and joined to the currently active vertical edge, + // potentially closing a hole. + // + // 6. Solid on the left of the vertical partion before the current position and solid to the right above and below + // |### + // |### + // ###|### + // ###|### + // The horizontal edge from the left is found and turns upward because of the vertical right edge to become + // the currently active vertical edge. + // + // 7. Solid on the right of the vertical partition after the current position and space elsewhere + // |### + // |### + // | + // | + // Create two new ActiveTails, one is added to the horizontal edges and the other becomes the vertical currentTail + // + // 8. Solid on the right of the vertical partion before the current position and space elsewhere + // | + // | + // |### + // |### + // The currentTail vertical edge turns right and is added to the horizontal edges data + // + // 9. Solid to the right above and solid to the left above and below current position. + // ###|### + // ###|### + // ###| + // ###| + // The currentTail vertical edge turns right and is added to the horizontal edges data + // + // 10. Solid on the left of the vertical partion above and below the current position and solid to the right below + // ###| + // ###| + // ###|### + // ###|### + // Create two new ActiveTails, one is added to the horizontal edges data and the other becomes the vertical currentTail + // + // 11. Solid to the right above and solid to the left below current position. + // |### + // |### + // ###| + // ###| + // The currentTail vertical edge joins the horizontal edge from the left (may close a polygon) + // Create two new ActiveTails, one is added to the horizontal edges data and the other becomes the vertical currentTail + // + // 12. Solid on the left of the vertical partion above the current position and solid to the right below + // ###| + // ###| + // |### + // |### + // The currentTail vertical edge turns right and is added to the horizontal edges data. + // The horizontal edge from the left turns upward and becomes the currentTail vertical edge + // + template <bool orientT, typename Unit, typename polygon_concept_type> + inline void ScanLineToPolygonItrs<orientT, Unit, polygon_concept_type>:: + processEdges(iterator& beginOutput, iterator& endOutput, + Unit currentX, std::vector<interval_data<Unit> >& leftEdges, + std::vector<interval_data<Unit> >& rightEdges) { + clearOutput_(); + typename std::map<Unit, ActiveTail<Unit>*>::iterator nextMapItr = tailMap_.begin(); + //foreach edge + unsigned int leftIndex = 0; + unsigned int rightIndex = 0; + bool bottomAlreadyProcessed = false; + ActiveTail<Unit>* currentTail = 0; + const Unit UnitMax = (std::numeric_limits<Unit>::max)(); + while(leftIndex < leftEdges.size() || rightIndex < rightEdges.size()) { + interval_data<Unit> edges[2] = {interval_data<Unit> (UnitMax, UnitMax), interval_data<Unit> (UnitMax, UnitMax)}; + bool haveNextEdge = true; + if(leftIndex < leftEdges.size()) + edges[0] = leftEdges[leftIndex]; + else + haveNextEdge = false; + if(rightIndex < rightEdges.size()) + edges[1] = rightEdges[rightIndex]; + else + haveNextEdge = false; + bool trailingEdge = edges[1].get(LOW) < edges[0].get(LOW); + interval_data<Unit> & edge = edges[trailingEdge]; + interval_data<Unit> & nextEdge = edges[!trailingEdge]; + //process this edge + if(!bottomAlreadyProcessed) { + //assert currentTail = 0 + + //process the bottom end of this edge + typename std::map<Unit, ActiveTail<Unit>*>::iterator thisMapItr = findAtNext(tailMap_, nextMapItr, edge.get(LOW)); + if(thisMapItr != tailMap_.end()) { + //there is an edge in the map at the low end of this edge + //it needs to turn upward and become the current tail + ActiveTail<Unit>* tail = thisMapItr->second; + if(currentTail) { + //stitch currentTail into this tail + currentTail = tail->addHole(currentTail, fractureHoles_); + if(!fractureHoles_) + currentTail->pushCoordinate(currentX); + } else { + currentTail = tail; + currentTail->pushCoordinate(currentX); + } + //assert currentTail->getOrient() == VERTICAL + nextMapItr = thisMapItr; //set nextMapItr to the next position after this one + ++nextMapItr; + //remove thisMapItr from the map + tailMap_.erase(thisMapItr); + } else { + //there is no edge in the map at the low end of this edge + //we need to create one and another one to be the current vertical tail + //if this is a trailing edge then there is space to the right of the vertical edge + //so pass the inverse of trailingEdge to indicate solid to the right + std::pair<ActiveTail<Unit>*, ActiveTail<Unit>*> tailPair = + createActiveTailsAsPair(currentX, edge.get(LOW), !trailingEdge, currentTail, fractureHoles_); + currentTail = tailPair.first; + tailMap_.insert(nextMapItr, std::pair<Unit, ActiveTail<Unit>*>(edge.get(LOW), tailPair.second)); + // leave nextMapItr unchanged + } + + } + if(haveNextEdge && edge.get(HIGH) == nextEdge.get(LOW)) { + //the top of this edge is equal to the bottom of the next edge, process them both + bottomAlreadyProcessed = true; + typename std::map<Unit, ActiveTail<Unit>*>::iterator thisMapItr = findAtNext(tailMap_, nextMapItr, edge.get(HIGH)); + if(thisMapItr == tailMap_.end()) //assert this should never happen + return; + if(trailingEdge) { + //geometry at this position + // |## + // |## + // ----- + // ##| + // ##| + //current tail should join thisMapItr tail + ActiveTail<Unit>* tail = thisMapItr->second; + //pass false because they are being joined because space is to the right and it will close a solid figure + ActiveTail<Unit>::joinChains(currentTail, tail, false, outputPolygons_); + //two new tails are created, the vertical becomes current tail, the horizontal becomes thisMapItr tail + //pass true becuase they are created at the lower left corner of some solid + //pass null because there is no hole pointer possible + std::pair<ActiveTail<Unit>*, ActiveTail<Unit>*> tailPair = + createActiveTailsAsPair<Unit>(currentX, edge.get(HIGH), true, 0, fractureHoles_); + currentTail = tailPair.first; + thisMapItr->second = tailPair.second; + } else { + //geometry at this position + // ##| + // ##| + // ----- + // |## + // |## + //current tail should turn right + currentTail->pushCoordinate(edge.get(HIGH)); + //thisMapItr tail should turn up + thisMapItr->second->pushCoordinate(currentX); + //thisMapItr tail becomes current tail and current tail becomes thisMapItr tail + std::swap(currentTail, thisMapItr->second); + } + nextMapItr = thisMapItr; //set nextMapItr to the next position after this one + ++nextMapItr; + } else { + //there is a gap between the top of this edge and the bottom of the next, process the top of this edge + bottomAlreadyProcessed = false; + //process the top of this edge + typename std::map<Unit, ActiveTail<Unit>*>::iterator thisMapItr = findAtNext(tailMap_, nextMapItr, edge.get(HIGH)); + if(thisMapItr != tailMap_.end()) { + //thisMapItr is pointing to a horizontal edge in the map at the top of this vertical edge + //we need to join them and potentially close a figure + //assert currentTail != 0 + ActiveTail<Unit>* tail = thisMapItr->second; + //pass the opositve of trailing edge to mean that they are joined because of solid to the right + currentTail = ActiveTail<Unit>::joinChains(currentTail, tail, !trailingEdge, outputPolygons_); + nextMapItr = thisMapItr; //set nextMapItr to the next position after this one + ++nextMapItr; + if(currentTail) { + Unit nextItrY = UnitMax; + if(nextMapItr != tailMap_.end()) { + nextItrY = nextMapItr->first; + } + //for it to be a hole this must have been a left edge + Unit leftY = UnitMax; + if(leftIndex + 1 < leftEdges.size()) + leftY = leftEdges[leftIndex+1].get(LOW); + Unit rightY = nextEdge.get(LOW); + if(!haveNextEdge || (nextItrY < leftY && nextItrY < rightY)) { + //we need to add it to the next edge above it in the map + tail = nextMapItr->second; + tail = tail->addHole(currentTail, fractureHoles_); + if(fractureHoles_) { + //some small additional work stitching in the filament + tail->pushCoordinate(nextItrY); + nextMapItr->second = tail; + } + //set current tail to null + currentTail = 0; + } + } + //delete thisMapItr from the map + tailMap_.erase(thisMapItr); + } else { + //currentTail must turn right and be added into the map + currentTail->pushCoordinate(edge.get(HIGH)); + //assert currentTail->getOrient() == HORIZONTAL + tailMap_.insert(nextMapItr, std::pair<Unit, ActiveTail<Unit>*>(edge.get(HIGH), currentTail)); + //set currentTail to null + currentTail = 0; + //leave nextMapItr unchanged, it is still next + } + } + + //increment index + leftIndex += !trailingEdge; + rightIndex += trailingEdge; + } //end while + beginOutput = outputPolygons_.begin(); + endOutput = outputPolygons_.end(); + } //end function + + template<bool orientT, typename Unit, typename polygon_concept_type> + inline void ScanLineToPolygonItrs<orientT, Unit, polygon_concept_type>::clearOutput_() { + for(std::size_t i = 0; i < outputPolygons_.size(); ++i) { + ActiveTail<Unit>* at1 = outputPolygons_[i].yield(); + const std::list<ActiveTail<Unit>*>& holes = at1->getHoles(); + for(typename std::list<ActiveTail<Unit>*>::const_iterator litr = holes.begin(); litr != holes.end(); ++litr) { + //delete the hole + (*litr)->destroyContents(); + destroyActiveTail((*litr)->getOtherActiveTail()); + destroyActiveTail((*litr)); + } + //delete the polygon + at1->destroyContents(); + //at2 contents are the same as at1, so it should not destroy them + destroyActiveTail((at1)->getOtherActiveTail()); + destroyActiveTail(at1); + } + outputPolygons_.clear(); + } + +} //polygon_formation namespace + + template <bool orientT, typename Unit> + struct geometry_concept<polygon_formation::PolyLinePolygonWithHolesData<orientT, Unit> > { + typedef polygon_90_with_holes_concept type; + }; + + template <bool orientT, typename Unit> + struct geometry_concept<polygon_formation::PolyLineHoleData<orientT, Unit> > { + typedef polygon_90_concept type; + }; + + //public API to access polygon formation algorithm + template <typename output_container, typename iterator_type, typename concept_type> + unsigned int get_polygons(output_container& container, iterator_type begin, iterator_type end, + orientation_2d orient, bool fracture_holes, concept_type ) { + typedef typename output_container::value_type polygon_type; + typedef typename std::iterator_traits<iterator_type>::value_type::first_type coordinate_type; + polygon_type poly; + unsigned int countPolygons = 0; + typedef typename geometry_concept<polygon_type>::type polygon_concept_type; + polygon_formation::ScanLineToPolygonItrs<true, coordinate_type, polygon_concept_type> scanlineToPolygonItrsV(fracture_holes); + polygon_formation::ScanLineToPolygonItrs<false, coordinate_type, polygon_concept_type> scanlineToPolygonItrsH(fracture_holes); + std::vector<interval_data<coordinate_type> > leftEdges; + std::vector<interval_data<coordinate_type> > rightEdges; + coordinate_type prevPos = (std::numeric_limits<coordinate_type>::max)(); + coordinate_type prevY = (std::numeric_limits<coordinate_type>::max)(); + int count = 0; + for(iterator_type itr = begin; + itr != end; ++ itr) { + coordinate_type pos = (*itr).first; + if(pos != prevPos) { + if(orient == VERTICAL) { + typename polygon_formation::ScanLineToPolygonItrs<true, coordinate_type, polygon_concept_type>::iterator itrPoly, itrPolyEnd; + scanlineToPolygonItrsV.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges); + for( ; itrPoly != itrPolyEnd; ++ itrPoly) { + ++countPolygons; + assign(poly, *itrPoly); + container.insert(container.end(), poly); + } + } else { + typename polygon_formation::ScanLineToPolygonItrs<false, coordinate_type, polygon_concept_type>::iterator itrPoly, itrPolyEnd; + scanlineToPolygonItrsH.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges); + for( ; itrPoly != itrPolyEnd; ++ itrPoly) { + ++countPolygons; + assign(poly, *itrPoly); + container.insert(container.end(), poly); + } + } + leftEdges.clear(); + rightEdges.clear(); + prevPos = pos; + prevY = (*itr).second.first; + count = (*itr).second.second; + continue; + } + coordinate_type y = (*itr).second.first; + if(count != 0 && y != prevY) { + std::pair<interval_data<coordinate_type>, int> element(interval_data<coordinate_type>(prevY, y), count); + if(element.second == 1) { + if(leftEdges.size() && leftEdges.back().high() == element.first.low()) { + encompass(leftEdges.back(), element.first); + } else { + leftEdges.push_back(element.first); + } + } else { + if(rightEdges.size() && rightEdges.back().high() == element.first.low()) { + encompass(rightEdges.back(), element.first); + } else { + rightEdges.push_back(element.first); + } + } + + } + prevY = y; + count += (*itr).second.second; + } + if(orient == VERTICAL) { + typename polygon_formation::ScanLineToPolygonItrs<true, coordinate_type, polygon_concept_type>::iterator itrPoly, itrPolyEnd; + scanlineToPolygonItrsV.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges); + for( ; itrPoly != itrPolyEnd; ++ itrPoly) { + ++countPolygons; + assign(poly, *itrPoly); + container.insert(container.end(), poly); + } + } else { + typename polygon_formation::ScanLineToPolygonItrs<false, coordinate_type, polygon_concept_type>::iterator itrPoly, itrPolyEnd; + scanlineToPolygonItrsH.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges); + for( ; itrPoly != itrPolyEnd; ++ itrPoly) { + ++countPolygons; + assign(poly, *itrPoly); + container.insert(container.end(), poly); + } + } + return countPolygons; + } + +} +} +#endif + diff --git a/boost/polygon/detail/polygon_set_view.hpp b/boost/polygon/detail/polygon_set_view.hpp new file mode 100644 index 0000000000..693acc4177 --- /dev/null +++ b/boost/polygon/detail/polygon_set_view.hpp @@ -0,0 +1,213 @@ +/* + 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_POLYGON_SET_VIEW_HPP +#define BOOST_POLYGON_POLYGON_SET_VIEW_HPP +namespace boost { namespace polygon{ + + + template <typename coordinate_type> + inline void polygon_set_data<coordinate_type>::clean() const { + if(dirty_) { + polygon_45_set_data<coordinate_type> tmp; + //very important: + //the 45 degree algorithm does not satisfy + //the precondition of arbitrary polygon formation + //that vertices be "linearly consistent" + //therefore it doesn't work to fall back on 45-degree + //booleans for arbitrary angle polygons + if(0) { //downcast(tmp) ) { + tmp.clean(); + data_.clear(); + is_45_ = true; + polygon_set_data<coordinate_type> tmp2; + tmp2.insert(tmp); + data_.swap(tmp2.data_); + dirty_ = false; + sort(); + } else { + sort(); + arbitrary_boolean_op<coordinate_type> abo; + polygon_set_data<coordinate_type> tmp2; + abo.execute(tmp2, begin(), end(), end(), end(), 0); + data_.swap(tmp2.data_); + is_45_ = tmp2.is_45_; + dirty_ = false; + } + } + } + + template <> + inline void polygon_set_data<double>::clean() const { + if(dirty_) { + sort(); + arbitrary_boolean_op<double> abo; + polygon_set_data<double> tmp2; + abo.execute(tmp2, begin(), end(), end(), end(), 0); + data_.swap(tmp2.data_); + is_45_ = tmp2.is_45_; + dirty_ = false; + } + } + + template <typename value_type, typename arg_type> + inline void insert_into_view_arg(value_type& dest, const arg_type& arg); + + template <typename ltype, typename rtype, int op_type> + class polygon_set_view; + + template <typename ltype, typename rtype, int op_type> + struct polygon_set_traits<polygon_set_view<ltype, rtype, op_type> > { + typedef typename polygon_set_view<ltype, rtype, op_type>::coordinate_type coordinate_type; + typedef typename polygon_set_view<ltype, rtype, op_type>::iterator_type iterator_type; + typedef typename polygon_set_view<ltype, rtype, op_type>::operator_arg_type operator_arg_type; + + static inline iterator_type begin(const polygon_set_view<ltype, rtype, op_type>& polygon_set); + static inline iterator_type end(const polygon_set_view<ltype, rtype, op_type>& polygon_set); + + static inline bool clean(const polygon_set_view<ltype, rtype, op_type>& polygon_set); + + static inline bool sort(const polygon_set_view<ltype, rtype, op_type>& polygon_set); + }; + + //template <typename value_type, typename geometry_type_1, typename geometry_type_2, int op_type> + //void execute_boolean_op(value_type& output_, const geometry_type_1& lvalue_, const geometry_type_2& rvalue_, + // double coord) { + // typedef geometry_type_1 ltype; + // typedef geometry_type_2 rtype; + // typedef typename polygon_set_traits<ltype>::coordinate_type coordinate_type; + // value_type linput_; + // value_type rinput_; + // insert_into_view_arg(linput_, lvalue_); + // insert_into_view_arg(rinput_, rvalue_); + // arbitrary_boolean_op<coordinate_type> abo; + // abo.execute(output_, linput_.begin(), linput_.end(), + // rinput_.begin(), rinput_.end(), op_type); + //} + + template <typename value_type, typename geometry_type_1, typename geometry_type_2, int op_type> + void execute_boolean_op(value_type& output_, const geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { + typedef geometry_type_1 ltype; + typedef geometry_type_2 rtype; + typedef typename polygon_set_traits<ltype>::coordinate_type coordinate_type; + value_type linput_; + value_type rinput_; + insert_into_view_arg(linput_, lvalue_); + insert_into_view_arg(rinput_, rvalue_); + polygon_45_set_data<coordinate_type> l45, r45, o45; + if(linput_.downcast(l45) && rinput_.downcast(r45)) { + //the op codes are screwed up between 45 and arbitrary +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op_type < 2) + l45.template applyAdaptiveBoolean_<op_type>(o45, r45); + else if(op_type == 2) + l45.template applyAdaptiveBoolean_<3>(o45, r45); + else + l45.template applyAdaptiveBoolean_<2>(o45, r45); +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + output_.insert(o45); + } else { + arbitrary_boolean_op<coordinate_type> abo; + abo.execute(output_, linput_.begin(), linput_.end(), + rinput_.begin(), rinput_.end(), op_type); + } + } + + template <typename ltype, typename rtype, int op_type> + class polygon_set_view { + public: + typedef typename polygon_set_traits<ltype>::coordinate_type coordinate_type; + typedef polygon_set_data<coordinate_type> value_type; + typedef typename value_type::iterator_type iterator_type; + typedef polygon_set_view operator_arg_type; + private: + const ltype& lvalue_; + const rtype& rvalue_; + mutable value_type output_; + mutable bool evaluated_; + polygon_set_view& operator=(const polygon_set_view&); + public: + polygon_set_view(const ltype& lvalue, + const rtype& rvalue ) : + lvalue_(lvalue), rvalue_(rvalue), output_(), evaluated_(false) {} + + // get iterator to begin vertex data + public: + const value_type& value() const { + if(!evaluated_) { + evaluated_ = true; + execute_boolean_op<value_type, ltype, rtype, op_type>(output_, lvalue_, rvalue_); + } + return output_; + } + public: + iterator_type begin() const { return value().begin(); } + iterator_type end() const { return value().end(); } + + bool dirty() const { return false; } //result of a boolean is clean + bool sorted() const { return true; } //result of a boolean is sorted + + void sort() const {} //is always sorted + }; + + template <typename ltype, typename rtype, int op_type> + typename polygon_set_traits<polygon_set_view<ltype, rtype, op_type> >::iterator_type + polygon_set_traits<polygon_set_view<ltype, rtype, op_type> >:: + begin(const polygon_set_view<ltype, rtype, op_type>& polygon_set) { + return polygon_set.begin(); + } + template <typename ltype, typename rtype, int op_type> + typename polygon_set_traits<polygon_set_view<ltype, rtype, op_type> >::iterator_type + polygon_set_traits<polygon_set_view<ltype, rtype, op_type> >:: + end(const polygon_set_view<ltype, rtype, op_type>& polygon_set) { + return polygon_set.end(); + } + template <typename ltype, typename rtype, int op_type> + bool polygon_set_traits<polygon_set_view<ltype, rtype, op_type> >:: + clean(const polygon_set_view<ltype, rtype, op_type>& ) { + return true; } + template <typename ltype, typename rtype, int op_type> + bool polygon_set_traits<polygon_set_view<ltype, rtype, op_type> >:: + sort(const polygon_set_view<ltype, rtype, op_type>& ) { + return true; } + + template <typename value_type, typename arg_type> + inline void insert_into_view_arg(value_type& dest, const arg_type& arg) { + typedef typename polygon_set_traits<arg_type>::iterator_type literator; + literator itr1, itr2; + itr1 = polygon_set_traits<arg_type>::begin(arg); + itr2 = polygon_set_traits<arg_type>::end(arg); + dest.insert(itr1, itr2); + } + + template <typename geometry_type_1, typename geometry_type_2, int op_type> + geometry_type_1& self_assignment_boolean_op(geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { + typedef geometry_type_1 ltype; + typedef typename polygon_set_traits<ltype>::coordinate_type coordinate_type; + typedef polygon_set_data<coordinate_type> value_type; + value_type output_; + execute_boolean_op<value_type, geometry_type_1, geometry_type_2, op_type>(output_, lvalue_, rvalue_); + polygon_set_mutable_traits<geometry_type_1>::set(lvalue_, output_.begin(), output_.end()); + return lvalue_; + } + + // copy constructor + template <typename coordinate_type> + template <typename ltype, typename rtype, int op_type> + polygon_set_data<coordinate_type>::polygon_set_data(const polygon_set_view<ltype, rtype, op_type>& that) : + data_(that.value().data_), dirty_(that.value().dirty_), unsorted_(that.value().unsorted_), is_45_(that.value().is_45_) {} + + template <typename ltype, typename rtype, int op_type> + struct geometry_concept<polygon_set_view<ltype, rtype, op_type> > { typedef polygon_set_concept type; }; +} +} +#endif + diff --git a/boost/polygon/detail/polygon_simplify.hpp b/boost/polygon/detail/polygon_simplify.hpp new file mode 100644 index 0000000000..c9a92f3e6f --- /dev/null +++ b/boost/polygon/detail/polygon_simplify.hpp @@ -0,0 +1,116 @@ +// Copyright 2011, Andrew Ross +// +// 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_DETAIL_SIMPLIFY_HPP +#define BOOST_POLYGON_DETAIL_SIMPLIFY_HPP +#include <vector> + +namespace boost { namespace polygon { namespace detail { namespace simplify_detail { + + // Does a simplification/optimization pass on the polygon. If a given + // vertex lies within "len" of the line segment joining its neighbor + // vertices, it is removed. + template <typename T> //T is a model of point concept + std::size_t simplify(std::vector<T>& dst, const std::vector<T>& src, + typename coordinate_traits< + typename point_traits<T>::coordinate_type + >::coordinate_distance len) + { + using namespace boost::polygon; + typedef typename point_traits<T>::coordinate_type coordinate_type; + typedef typename coordinate_traits<coordinate_type>::area_type ftype; + typedef typename std::vector<T>::const_iterator iter; + + std::vector<T> out; + out.reserve(src.size()); + dst = src; + std::size_t final_result = 0; + std::size_t orig_size = src.size(); + + //I can't use == if T doesn't provide it, so use generic point concept compare + bool closed = equivalence(src.front(), src.back()); + + //we need to keep smoothing until we don't find points to remove + //because removing points in the first iteration through the + //polygon may leave it in a state where more removal is possible + bool not_done = true; + while(not_done) { + if(dst.size() < 3) { + dst.clear(); + return orig_size; + } + + // Start with the second, test for the last point + // explicitly, and exit after looping back around to the first. + ftype len2 = ftype(len) * ftype(len); + for(iter prev=dst.begin(), i=prev+1, next; /**/; i = next) { + next = i+1; + if(next == dst.end()) + next = dst.begin(); + + // points A, B, C + ftype ax = x(*prev), ay = y(*prev); + ftype bx = x(*i), by = y(*i); + ftype cx = x(*next), cy = y(*next); + + // vectors AB, BC and AC: + ftype abx = bx-ax, aby = by-ay; + ftype bcx = cx-bx, bcy = cy-by; + ftype acx = cx-ax, acy = cy-ay; + + // dot products + ftype ab_ab = abx*abx + aby*aby; + ftype bc_bc = bcx*bcx + bcy*bcy; + ftype ac_ac = acx*acx + acy*acy; + ftype ab_ac = abx*acx + aby*acy; + + // projection of AB along AC + ftype projf = ab_ac / ac_ac; + ftype projx = acx * projf, projy = acy * projf; + + // perpendicular vector from the line AC to point B (i.e. AB - proj) + ftype perpx = abx - projx, perpy = aby - projy; + + // Squared fractional distance of projection. FIXME: can + // remove this division, the decisions below can be made with + // just the sign of the quotient and a check to see if + // abs(numerator) is greater than abs(divisor). + ftype f2 = (projx*acx + projy*acx) / ac_ac; + + // Square of the relevant distance from point B: + ftype dist2; + if (f2 < 0) dist2 = ab_ab; + else if(f2 > 1) dist2 = bc_bc; + else dist2 = perpx*perpx + perpy*perpy; + + if(dist2 > len2) { + prev = i; // bump prev, we didn't remove the segment + out.push_back(*i); + } + + if(i == dst.begin()) + break; + } + std::size_t result = dst.size() - out.size(); + if(result == 0) { + not_done = false; + } else { + final_result += result; + dst = out; + out.clear(); + } + } //end of while loop + if(closed) { + //if the input was closed we want the output to be closed + --final_result; + dst.push_back(dst.front()); + } + return final_result; + } + + +}}}} + +#endif diff --git a/boost/polygon/detail/polygon_sort_adaptor.hpp b/boost/polygon/detail/polygon_sort_adaptor.hpp new file mode 100644 index 0000000000..40f16a7e1b --- /dev/null +++ b/boost/polygon/detail/polygon_sort_adaptor.hpp @@ -0,0 +1,67 @@ +/* + 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_SORT_ADAPTOR_HPP +#define BOOST_POLYGON_SORT_ADAPTOR_HPP +#ifdef __ICC +#pragma warning(disable:2022) +#pragma warning(disable:2023) +#endif + +#include <algorithm> + +//! @brief gtlsort_adaptor default implementation that calls std::sort +namespace boost { + namespace polygon { + + template<typename iterator_type> + struct dummy_to_delay_instantiation{ + typedef int unit_type; // default GTL unit + }; + + //! @brief gtlsort_adaptor default implementation that calls std::sort + template<typename T> + struct gtlsort_adaptor { + //! @brief wrapper that mimics std::sort() function and takes + // the same arguments + template<typename RandomAccessIterator_Type> + static void sort(RandomAccessIterator_Type _First, + RandomAccessIterator_Type _Last) + { + std::sort(_First, _Last); + } + //! @brief wrapper that mimics std::sort() function overload and takes + // the same arguments + template<typename RandomAccessIterator_Type, typename Pred_Type> + static void sort(RandomAccessIterator_Type _First, + RandomAccessIterator_Type _Last, + const Pred_Type& _Comp) + { + std::sort(_First, _Last, _Comp); + } + }; + + //! @brief user level wrapper for sorting quantities + template <typename iter_type> + void gtlsort(iter_type _b_, iter_type _e_) + { + gtlsort_adaptor<typename dummy_to_delay_instantiation<iter_type>::unit_type>::sort(_b_, _e_); + } + + //! @brief user level wrapper for sorting quantities that takes predicate + // as additional argument + template <typename iter_type, typename pred_type> + void gtlsort(iter_type _b_, iter_type _e_, const pred_type& _pred_) + { + gtlsort_adaptor<typename dummy_to_delay_instantiation<iter_type>::unit_type>::sort(_b_, _e_, _pred_); + } + + + + } // namespace polygon +} // namespace boost +#endif diff --git a/boost/polygon/detail/property_merge.hpp b/boost/polygon/detail/property_merge.hpp new file mode 100644 index 0000000000..77f2614753 --- /dev/null +++ b/boost/polygon/detail/property_merge.hpp @@ -0,0 +1,588 @@ +/* + 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_PROPERTY_MERGE_HPP +#define BOOST_POLYGON_PROPERTY_MERGE_HPP +namespace boost { namespace polygon{ + +template <typename coordinate_type> +class property_merge_point { +private: + coordinate_type x_, y_; +public: + inline property_merge_point() : x_(), y_() {} + inline property_merge_point(coordinate_type x, coordinate_type y) : x_(x), y_(y) {} + //use builtin assign and copy + inline bool operator==(const property_merge_point& that) const { return x_ == that.x_ && y_ == that.y_; } + inline bool operator!=(const property_merge_point& that) const { return !((*this) == that); } + inline bool operator<(const property_merge_point& that) const { + if(x_ < that.x_) return true; + if(x_ > that.x_) return false; + return y_ < that.y_; + } + inline coordinate_type x() const { return x_; } + inline coordinate_type y() const { return y_; } + inline void x(coordinate_type value) { x_ = value; } + inline void y(coordinate_type value) { y_ = value; } +}; + +template <typename coordinate_type> +class property_merge_interval { +private: + coordinate_type low_, high_; +public: + inline property_merge_interval() : low_(), high_() {} + inline property_merge_interval(coordinate_type low, coordinate_type high) : low_(low), high_(high) {} + //use builtin assign and copy + inline bool operator==(const property_merge_interval& that) const { return low_ == that.low_ && high_ == that.high_; } + inline bool operator!=(const property_merge_interval& that) const { return !((*this) == that); } + inline bool operator<(const property_merge_interval& that) const { + if(low_ < that.low_) return true; + if(low_ > that.low_) return false; + return high_ < that.high_; + } + inline coordinate_type low() const { return low_; } + inline coordinate_type high() const { return high_; } + inline void low(coordinate_type value) { low_ = value; } + inline void high(coordinate_type value) { high_ = value; } +}; + +template <typename coordinate_type, typename property_type, typename polygon_set_type, typename keytype = std::set<property_type> > +class merge_scanline { +public: + //definitions + + typedef keytype property_set; + typedef std::vector<std::pair<property_type, int> > property_map; + typedef std::pair<property_merge_point<coordinate_type>, std::pair<property_type, int> > vertex_property; + typedef std::pair<property_merge_point<coordinate_type>, property_map> vertex_data; + typedef std::vector<vertex_property> property_merge_data; + //typedef std::map<property_set, polygon_set_type> Result; + typedef std::map<coordinate_type, property_map> scanline_type; + typedef typename scanline_type::iterator scanline_iterator; + typedef std::pair<property_merge_interval<coordinate_type>, std::pair<property_set, property_set> > edge_property; + typedef std::vector<edge_property> edge_property_vector; + + //static public member functions + + template <typename iT, typename orientation_2d_type> + static inline void + populate_property_merge_data(property_merge_data& pmd, iT input_begin, iT input_end, + const property_type& property, orientation_2d_type orient) { + for( ; input_begin != input_end; ++input_begin) { + std::pair<property_merge_point<coordinate_type>, std::pair<property_type, int> > element; + if(orient == HORIZONTAL) + element.first = property_merge_point<coordinate_type>((*input_begin).second.first, (*input_begin).first); + else + element.first = property_merge_point<coordinate_type>((*input_begin).first, (*input_begin).second.first); + element.second.first = property; + element.second.second = (*input_begin).second.second; + pmd.push_back(element); + } + } + + //public member functions + + merge_scanline() : output(), scanline(), currentVertex(), tmpVector(), previousY(), countFromBelow(), scanlinePosition() {} + merge_scanline(const merge_scanline& that) : + output(that.output), + scanline(that.scanline), + currentVertex(that.currentVertex), + tmpVector(that.tmpVector), + previousY(that.previousY), + countFromBelow(that.countFromBelow), + scanlinePosition(that.scanlinePosition) + {} + merge_scanline& operator=(const merge_scanline& that) { + output = that.output; + scanline = that.scanline; + currentVertex = that.currentVertex; + tmpVector = that.tmpVector; + previousY = that.previousY; + countFromBelow = that.countFromBelow; + scanlinePosition = that.scanlinePosition; + return *this; + } + + template <typename result_type> + inline void perform_merge(result_type& result, property_merge_data& data) { + if(data.empty()) return; + //sort + gtlsort(data.begin(), data.end(), less_vertex_data<vertex_property>()); + //scanline + bool firstIteration = true; + scanlinePosition = scanline.end(); + for(std::size_t i = 0; i < data.size(); ++i) { + if(firstIteration) { + mergeProperty(currentVertex.second, data[i].second); + currentVertex.first = data[i].first; + firstIteration = false; + } else { + if(data[i].first != currentVertex.first) { + if(data[i].first.x() != currentVertex.first.x()) { + processVertex(output); + //std::cout << scanline.size() << " "; + countFromBelow.clear(); //should already be clear + writeOutput(currentVertex.first.x(), result, output); + currentVertex.second.clear(); + mergeProperty(currentVertex.second, data[i].second); + currentVertex.first = data[i].first; + //std::cout << assertRedundant(scanline) << "/" << scanline.size() << " "; + } else { + processVertex(output); + currentVertex.second.clear(); + mergeProperty(currentVertex.second, data[i].second); + currentVertex.first = data[i].first; + } + } else { + mergeProperty(currentVertex.second, data[i].second); + } + } + } + processVertex(output); + writeOutput(currentVertex.first.x(), result, output); + //std::cout << assertRedundant(scanline) << "/" << scanline.size() << "\n"; + //std::cout << scanline.size() << "\n"; + } + +private: + //private supporting types + + template <class T> + class less_vertex_data { + public: + less_vertex_data() {} + bool operator()(const T& lvalue, const T& rvalue) const { + if(lvalue.first.x() < rvalue.first.x()) return true; + if(lvalue.first.x() > rvalue.first.x()) return false; + if(lvalue.first.y() < rvalue.first.y()) return true; + return false; + } + }; + + template <typename T> + struct lessPropertyCount { + lessPropertyCount() {} + bool operator()(const T& a, const T& b) { + return a.first < b.first; + } + }; + + //private static member functions + + static inline void mergeProperty(property_map& lvalue, std::pair<property_type, int>& rvalue) { + typename property_map::iterator itr = std::lower_bound(lvalue.begin(), lvalue.end(), rvalue, + lessPropertyCount<std::pair<property_type, int> >()); + if(itr == lvalue.end() || + (*itr).first != rvalue.first) { + lvalue.insert(itr, rvalue); + } else { + (*itr).second += rvalue.second; + if((*itr).second == 0) + lvalue.erase(itr); + } +// if(assertSorted(lvalue)) { +// std::cout << "in mergeProperty\n"; +// exit(0); +// } + } + +// static inline bool assertSorted(property_map& pset) { +// bool result = false; +// for(std::size_t i = 1; i < pset.size(); ++i) { +// if(pset[i] < pset[i-1]) { +// std::cout << "Out of Order Error "; +// result = true; +// } +// if(pset[i].first == pset[i-1].first) { +// std::cout << "Duplicate Property Error "; +// result = true; +// } +// if(pset[0].second == 0 || pset[1].second == 0) { +// std::cout << "Empty Property Error "; +// result = true; +// } +// } +// return result; +// } + + static inline void setProperty(property_set& pset, property_map& pmap) { + for(typename property_map::iterator itr = pmap.begin(); itr != pmap.end(); ++itr) { + if((*itr).second > 0) { + pset.insert(pset.end(), (*itr).first); + } + } + } + + //private data members + + edge_property_vector output; + scanline_type scanline; + vertex_data currentVertex; + property_map tmpVector; + coordinate_type previousY; + property_map countFromBelow; + scanline_iterator scanlinePosition; + + //private member functions + + inline void mergeCount(property_map& lvalue, property_map& rvalue) { + typename property_map::iterator litr = lvalue.begin(); + typename property_map::iterator ritr = rvalue.begin(); + tmpVector.clear(); + while(litr != lvalue.end() && ritr != rvalue.end()) { + if((*litr).first <= (*ritr).first) { + if(!tmpVector.empty() && + (*litr).first == tmpVector.back().first) { + tmpVector.back().second += (*litr).second; + } else { + tmpVector.push_back(*litr); + } + ++litr; + } else if((*ritr).first <= (*litr).first) { + if(!tmpVector.empty() && + (*ritr).first == tmpVector.back().first) { + tmpVector.back().second += (*ritr).second; + } else { + tmpVector.push_back(*ritr); + } + ++ritr; + } + } + while(litr != lvalue.end()) { + if(!tmpVector.empty() && + (*litr).first == tmpVector.back().first) { + tmpVector.back().second += (*litr).second; + } else { + tmpVector.push_back(*litr); + } + ++litr; + } + while(ritr != rvalue.end()) { + if(!tmpVector.empty() && + (*ritr).first == tmpVector.back().first) { + tmpVector.back().second += (*ritr).second; + } else { + tmpVector.push_back(*ritr); + } + ++ritr; + } + lvalue.clear(); + for(std::size_t i = 0; i < tmpVector.size(); ++i) { + if(tmpVector[i].second != 0) { + lvalue.push_back(tmpVector[i]); + } + } +// if(assertSorted(lvalue)) { +// std::cout << "in mergeCount\n"; +// exit(0); +// } + } + + inline void processVertex(edge_property_vector& output) { + if(!countFromBelow.empty()) { + //we are processing an interval of change in scanline state between + //previous vertex position and current vertex position where + //count from below represents the change on the interval + //foreach scanline element from previous to current we + //write the interval on the scanline that is changing + //the old value and the new value to output + property_merge_interval<coordinate_type> currentInterval(previousY, currentVertex.first.y()); + coordinate_type currentY = currentInterval.low(); + if(scanlinePosition == scanline.end() || + (*scanlinePosition).first != previousY) { + scanlinePosition = scanline.lower_bound(previousY); + } + scanline_iterator previousScanlinePosition = scanlinePosition; + ++scanlinePosition; + while(scanlinePosition != scanline.end()) { + coordinate_type elementY = (*scanlinePosition).first; + if(elementY <= currentInterval.high()) { + property_map& countOnLeft = (*previousScanlinePosition).second; + edge_property element; + output.push_back(element); + output.back().first = property_merge_interval<coordinate_type>((*previousScanlinePosition).first, elementY); + setProperty(output.back().second.first, countOnLeft); + mergeCount(countOnLeft, countFromBelow); + setProperty(output.back().second.second, countOnLeft); + if(output.back().second.first == output.back().second.second) { + output.pop_back(); //it was an internal vertical edge, not to be output + } + else if(output.size() > 1) { + edge_property& secondToLast = output[output.size()-2]; + if(secondToLast.first.high() == output.back().first.low() && + secondToLast.second.first == output.back().second.first && + secondToLast.second.second == output.back().second.second) { + //merge output onto previous output because properties are + //identical on both sides implying an internal horizontal edge + secondToLast.first.high(output.back().first.high()); + output.pop_back(); + } + } + if(previousScanlinePosition == scanline.begin()) { + if(countOnLeft.empty()) { + scanline.erase(previousScanlinePosition); + } + } else { + scanline_iterator tmpitr = previousScanlinePosition; + --tmpitr; + if((*tmpitr).second == (*previousScanlinePosition).second) + scanline.erase(previousScanlinePosition); + } + + } else if(currentY < currentInterval.high()){ + //elementY > currentInterval.high() + //split the interval between previous and current scanline elements + std::pair<coordinate_type, property_map> elementScan; + elementScan.first = currentInterval.high(); + elementScan.second = (*previousScanlinePosition).second; + scanlinePosition = scanline.insert(scanlinePosition, elementScan); + continue; + } else { + break; + } + previousScanlinePosition = scanlinePosition; + currentY = previousY = elementY; + ++scanlinePosition; + if(scanlinePosition == scanline.end() && + currentY < currentInterval.high()) { + //insert a new element for top of range + std::pair<coordinate_type, property_map> elementScan; + elementScan.first = currentInterval.high(); + scanlinePosition = scanline.insert(scanline.end(), elementScan); + } + } + if(scanlinePosition == scanline.end() && + currentY < currentInterval.high()) { + //handle case where we iterated to end of the scanline + //we need to insert an element into the scanline at currentY + //with property value coming from below + //and another one at currentInterval.high() with empty property value + mergeCount(scanline[currentY], countFromBelow); + std::pair<coordinate_type, property_map> elementScan; + elementScan.first = currentInterval.high(); + scanline.insert(scanline.end(), elementScan); + + edge_property element; + output.push_back(element); + output.back().first = property_merge_interval<coordinate_type>(currentY, currentInterval.high()); + setProperty(output.back().second.second, countFromBelow); + mergeCount(countFromBelow, currentVertex.second); + } else { + mergeCount(countFromBelow, currentVertex.second); + if(countFromBelow.empty()) { + if(previousScanlinePosition == scanline.begin()) { + if((*previousScanlinePosition).second.empty()) { + scanline.erase(previousScanlinePosition); + //previousScanlinePosition = scanline.end(); + //std::cout << "ERASE_A "; + } + } else { + scanline_iterator tmpitr = previousScanlinePosition; + --tmpitr; + if((*tmpitr).second == (*previousScanlinePosition).second) { + scanline.erase(previousScanlinePosition); + //previousScanlinePosition = scanline.end(); + //std::cout << "ERASE_B "; + } + } + } + } + } else { + //count from below is empty, we are starting a new interval of change + countFromBelow = currentVertex.second; + scanlinePosition = scanline.lower_bound(currentVertex.first.y()); + if(scanlinePosition != scanline.end()) { + if((*scanlinePosition).first != currentVertex.first.y()) { + if(scanlinePosition != scanline.begin()) { + //decrement to get the lower position of the first interval this vertex intersects + --scanlinePosition; + //insert a new element into the scanline for the incoming vertex + property_map& countOnLeft = (*scanlinePosition).second; + std::pair<coordinate_type, property_map> element(currentVertex.first.y(), countOnLeft); + scanlinePosition = scanline.insert(scanlinePosition, element); + } else { + property_map countOnLeft; + std::pair<coordinate_type, property_map> element(currentVertex.first.y(), countOnLeft); + scanlinePosition = scanline.insert(scanlinePosition, element); + } + } + } else { + property_map countOnLeft; + std::pair<coordinate_type, property_map> element(currentVertex.first.y(), countOnLeft); + scanlinePosition = scanline.insert(scanlinePosition, element); + } + } + previousY = currentVertex.first.y(); + } + + template <typename T> + inline int assertRedundant(T& t) { + if(t.empty()) return 0; + int count = 0; + typename T::iterator itr = t.begin(); + if((*itr).second.empty()) + ++count; + typename T::iterator itr2 = itr; + ++itr2; + while(itr2 != t.end()) { + if((*itr).second == (*itr2).second) + ++count; + itr = itr2; + ++itr2; + } + return count; + } + + template <typename T> + inline void performExtract(T& result, property_merge_data& data) { + if(data.empty()) return; + //sort + gtlsort(data.begin(), data.end(), less_vertex_data<vertex_property>()); + + //scanline + bool firstIteration = true; + scanlinePosition = scanline.end(); + for(std::size_t i = 0; i < data.size(); ++i) { + if(firstIteration) { + mergeProperty(currentVertex.second, data[i].second); + currentVertex.first = data[i].first; + firstIteration = false; + } else { + if(data[i].first != currentVertex.first) { + if(data[i].first.x() != currentVertex.first.x()) { + processVertex(output); + //std::cout << scanline.size() << " "; + countFromBelow.clear(); //should already be clear + writeGraph(currentVertex.first.x(), result, output, scanline); + currentVertex.second.clear(); + mergeProperty(currentVertex.second, data[i].second); + currentVertex.first = data[i].first; + } else { + processVertex(output); + currentVertex.second.clear(); + mergeProperty(currentVertex.second, data[i].second); + currentVertex.first = data[i].first; + } + } else { + mergeProperty(currentVertex.second, data[i].second); + } + } + } + processVertex(output); + writeGraph(currentVertex.first.x(), result, output, scanline); + //std::cout << scanline.size() << "\n"; + } + + template <typename T> + inline void insertEdges(T& graph, property_set& p1, property_set& p2) { + for(typename property_set::iterator itr = p1.begin(); itr != p1.end(); ++itr) { + for(typename property_set::iterator itr2 = p2.begin(); itr2 != p2.end(); ++itr2) { + if(*itr != *itr2) { + graph[*itr].insert(*itr2); + graph[*itr2].insert(*itr); + } + } + } + } + + template <typename T> + inline void propertySetAbove(coordinate_type y, property_set& ps, T& scanline) { + ps.clear(); + typename T::iterator itr = scanline.find(y); + if(itr != scanline.end()) + setProperty(ps, (*itr).second); + } + + template <typename T> + inline void propertySetBelow(coordinate_type y, property_set& ps, T& scanline) { + ps.clear(); + typename T::iterator itr = scanline.find(y); + if(itr != scanline.begin()) { + --itr; + setProperty(ps, (*itr).second); + } + } + + template <typename T, typename T2> + inline void writeGraph(coordinate_type x, T& graph, edge_property_vector& output, T2& scanline) { + if(output.empty()) return; + edge_property* previousEdgeP = &(output[0]); + bool firstIteration = true; + property_set ps; + for(std::size_t i = 0; i < output.size(); ++i) { + edge_property& previousEdge = *previousEdgeP; + edge_property& edge = output[i]; + if(previousEdge.first.high() == edge.first.low()) { + //horizontal edge + insertEdges(graph, edge.second.first, previousEdge.second.first); + //corner 1 + insertEdges(graph, edge.second.first, previousEdge.second.second); + //other horizontal edge + insertEdges(graph, edge.second.second, previousEdge.second.second); + //corner 2 + insertEdges(graph, edge.second.second, previousEdge.second.first); + } else { + if(!firstIteration){ + //look up regions above previous edge + propertySetAbove(previousEdge.first.high(), ps, scanline); + insertEdges(graph, ps, previousEdge.second.first); + insertEdges(graph, ps, previousEdge.second.second); + } + //look up regions below current edge in the scanline + propertySetBelow(edge.first.high(), ps, scanline); + insertEdges(graph, ps, edge.second.first); + insertEdges(graph, ps, edge.second.second); + } + firstIteration = false; + //vertical edge + insertEdges(graph, edge.second.second, edge.second.first); + //shared region to left + insertEdges(graph, edge.second.second, edge.second.second); + //shared region to right + insertEdges(graph, edge.second.first, edge.second.first); + previousEdgeP = &(output[i]); + } + edge_property& previousEdge = *previousEdgeP; + propertySetAbove(previousEdge.first.high(), ps, scanline); + insertEdges(graph, ps, previousEdge.second.first); + insertEdges(graph, ps, previousEdge.second.second); + output.clear(); + } + + template <typename Result> + inline void writeOutput(coordinate_type x, Result& result, edge_property_vector& output) { + for(std::size_t i = 0; i < output.size(); ++i) { + edge_property& edge = output[i]; + //edge.second.first is the property set on the left of the edge + if(!edge.second.first.empty()) { + typename Result::iterator itr = result.find(edge.second.first); + if(itr == result.end()) { + std::pair<property_set, polygon_set_type> element(edge.second.first, polygon_set_type(VERTICAL)); + itr = result.insert(result.end(), element); + } + std::pair<interval_data<coordinate_type>, int> element2(interval_data<coordinate_type>(edge.first.low(), edge.first.high()), -1); //right edge of figure + (*itr).second.insert(x, element2); + } + if(!edge.second.second.empty()) { + //edge.second.second is the property set on the right of the edge + typename Result::iterator itr = result.find(edge.second.second); + if(itr == result.end()) { + std::pair<property_set, polygon_set_type> element(edge.second.second, polygon_set_type(VERTICAL)); + itr = result.insert(result.end(), element); + } + std::pair<interval_data<coordinate_type>, int> element3(interval_data<coordinate_type>(edge.first.low(), edge.first.high()), 1); //left edge of figure + (*itr).second.insert(x, element3); + } + } + output.clear(); + } +}; + +} +} +#endif diff --git a/boost/polygon/detail/property_merge_45.hpp b/boost/polygon/detail/property_merge_45.hpp new file mode 100644 index 0000000000..b85baf7f88 --- /dev/null +++ b/boost/polygon/detail/property_merge_45.hpp @@ -0,0 +1,160 @@ +/* + 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_PROPERTY_MERGE_45_HPP +#define BOOST_POLYGON_PROPERTY_MERGE_45_HPP +namespace boost { namespace polygon{ + + template <typename Unit, typename property_type> + struct polygon_45_property_merge { + + typedef point_data<Unit> Point; + typedef typename coordinate_traits<Unit>::manhattan_area_type LongUnit; + + template <typename property_map> + static inline void merge_property_maps(property_map& mp, const property_map& mp2, bool subtract = false) { + polygon_45_touch<Unit>::merge_property_maps(mp, mp2, subtract); + } + + class CountMerge { + public: + inline CountMerge() : counts() {} + //inline CountMerge(int count) { counts[0] = counts[1] = count; } + //inline CountMerge(int count1, int count2) { counts[0] = count1; counts[1] = count2; } + inline CountMerge(const CountMerge& count) : counts(count.counts) {} + inline bool operator==(const CountMerge& count) const { return counts == count.counts; } + inline bool operator!=(const CountMerge& count) const { return !((*this) == count); } + //inline CountMerge& operator=(int count) { counts[0] = counts[1] = count; return *this; } + inline CountMerge& operator=(const CountMerge& count) { counts = count.counts; return *this; } + inline int& operator[](property_type index) { + std::vector<std::pair<int, int> >::iterator itr = lower_bound(counts.begin(), counts.end(), std::make_pair(index, int(0))); + if(itr != counts.end() && itr->first == index) { + return itr->second; + } + itr = counts.insert(itr, std::make_pair(index, int(0))); + return itr->second; + } +// inline int operator[](int index) const { +// std::vector<std::pair<int, int> >::const_iterator itr = counts.begin(); +// for( ; itr != counts.end() && itr->first <= index; ++itr) { +// if(itr->first == index) { +// return itr->second; +// } +// } +// return 0; +// } + inline CountMerge& operator+=(const CountMerge& count){ + merge_property_maps(counts, count.counts, false); + return *this; + } + inline CountMerge& operator-=(const CountMerge& count){ + merge_property_maps(counts, count.counts, true); + return *this; + } + inline CountMerge operator+(const CountMerge& count) const { + return CountMerge(*this)+=count; + } + inline CountMerge operator-(const CountMerge& count) const { + return CountMerge(*this)-=count; + } + inline CountMerge invert() const { + CountMerge retval; + retval -= *this; + return retval; + } + std::vector<std::pair<property_type, int> > counts; + }; + + //output is a std::map<std::set<property_type>, polygon_45_set_data<Unit> > + struct merge_45_output_functor { + template <typename cT> + void operator()(cT& output, const CountMerge& count1, const CountMerge& count2, + const Point& pt, int rise, direction_1d end) { + typedef typename cT::key_type keytype; + keytype left; + keytype right; + int edgeType = end == LOW ? -1 : 1; + for(typename std::vector<std::pair<property_type, int> >::const_iterator itr = count1.counts.begin(); + itr != count1.counts.end(); ++itr) { + left.insert(left.end(), (*itr).first); + } + for(typename std::vector<std::pair<property_type, int> >::const_iterator itr = count2.counts.begin(); + itr != count2.counts.end(); ++itr) { + right.insert(right.end(), (*itr).first); + } + if(left == right) return; + if(!left.empty()) { + //std::cout << pt.x() << " " << pt.y() << " " << rise << " " << edgeType << std::endl; + output[left].insert_clean(typename boolean_op_45<Unit>::Vertex45(pt, rise, -edgeType)); + } + if(!right.empty()) { + //std::cout << pt.x() << " " << pt.y() << " " << rise << " " << -edgeType << std::endl; + output[right].insert_clean(typename boolean_op_45<Unit>::Vertex45(pt, rise, edgeType)); + } + } + }; + + typedef typename std::pair<Point, + typename boolean_op_45<Unit>::template Scan45CountT<CountMerge> > Vertex45Compact; + typedef std::vector<Vertex45Compact> MergeSetData; + + struct lessVertex45Compact { + bool operator()(const Vertex45Compact& l, const Vertex45Compact& r) { + return l.first < r.first; + } + }; + + template <typename output_type> + static void performMerge(output_type& result, MergeSetData& tsd) { + + gtlsort(tsd.begin(), tsd.end(), lessVertex45Compact()); + typedef std::vector<std::pair<Point, typename boolean_op_45<Unit>::template Scan45CountT<CountMerge> > > TSD; + TSD tsd_; + tsd_.reserve(tsd.size()); + for(typename MergeSetData::iterator itr = tsd.begin(); itr != tsd.end(); ) { + typename MergeSetData::iterator itr2 = itr; + ++itr2; + for(; itr2 != tsd.end() && itr2->first == itr->first; ++itr2) { + (itr->second) += (itr2->second); //accumulate + } + tsd_.push_back(std::make_pair(itr->first, itr->second)); + itr = itr2; + } + typename boolean_op_45<Unit>::template Scan45<CountMerge, merge_45_output_functor> scanline; + for(typename TSD::iterator itr = tsd_.begin(); itr != tsd_.end(); ) { + typename TSD::iterator itr2 = itr; + ++itr2; + while(itr2 != tsd_.end() && itr2->first.x() == itr->first.x()) { + ++itr2; + } + scanline.scan(result, itr, itr2); + itr = itr2; + } + } + + template <typename iT> + static void populateMergeSetData(MergeSetData& tsd, iT begin, iT end, property_type property) { + for( ; begin != end; ++begin) { + Vertex45Compact vertex; + vertex.first = typename Vertex45Compact::first_type(begin->pt.x() * 2, begin->pt.y() * 2); + tsd.push_back(vertex); + for(unsigned int i = 0; i < 4; ++i) { + if(begin->count[i]) { + tsd.back().second[i][property] += begin->count[i]; + } + } + } + } + + }; + + + +} +} + +#endif diff --git a/boost/polygon/detail/rectangle_formation.hpp b/boost/polygon/detail/rectangle_formation.hpp new file mode 100644 index 0000000000..d0ae180ea4 --- /dev/null +++ b/boost/polygon/detail/rectangle_formation.hpp @@ -0,0 +1,267 @@ +/* + 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_RECTANGLE_FORMATION_HPP +#define BOOST_POLYGON_RECTANGLE_FORMATION_HPP +namespace boost { namespace polygon{ + +namespace rectangle_formation { + template <class T> + class ScanLineToRects { + public: + typedef T rectangle_type; + typedef typename rectangle_traits<T>::coordinate_type coordinate_type; + typedef rectangle_data<coordinate_type> scan_rect_type; + private: + + typedef std::set<scan_rect_type, less_rectangle_concept<scan_rect_type, scan_rect_type> > ScanData; + ScanData scanData_; + bool haveCurrentRect_; + scan_rect_type currentRect_; + orientation_2d orient_; + typename rectangle_traits<T>::coordinate_type currentCoordinate_; + public: + inline ScanLineToRects() : scanData_(), haveCurrentRect_(), currentRect_(), orient_(), currentCoordinate_() {} + + inline ScanLineToRects(orientation_2d orient, rectangle_type model) : + scanData_(orientation_2d(orient.to_int() ? VERTICAL : HORIZONTAL)), + haveCurrentRect_(false), currentRect_(), orient_(orient), currentCoordinate_() { + assign(currentRect_, model); + currentCoordinate_ = (std::numeric_limits<coordinate_type>::max)(); + } + + template <typename CT> + inline ScanLineToRects& processEdge(CT& rectangles, const interval_data<coordinate_type>& edge); + + inline ScanLineToRects& nextMajorCoordinate(coordinate_type currentCoordinate) { + if(haveCurrentRect_) { + scanData_.insert(scanData_.end(), currentRect_); + haveCurrentRect_ = false; + } + currentCoordinate_ = currentCoordinate; + return *this; + } + + }; + + template <class CT, class ST, class rectangle_type, typename interval_type, typename coordinate_type> inline CT& + processEdge_(CT& rectangles, ST& scanData, const interval_type& edge, + bool& haveCurrentRect, rectangle_type& currentRect, coordinate_type currentCoordinate, orientation_2d orient) + { + typedef typename CT::value_type result_type; + bool edgeProcessed = false; + if(!scanData.empty()) { + + //process all rectangles in the scanData that touch the edge + typename ST::iterator dataIter = scanData.lower_bound(rectangle_type(edge, edge)); + //decrement beginIter until its low is less than edge's low + while((dataIter == scanData.end() || (*dataIter).get(orient).get(LOW) > edge.get(LOW)) && + dataIter != scanData.begin()) + { + --dataIter; + } + //process each rectangle until the low end of the rectangle + //is greater than the high end of the edge + while(dataIter != scanData.end() && + (*dataIter).get(orient).get(LOW) <= edge.get(HIGH)) + { + const rectangle_type& rect = *dataIter; + //if the rectangle data intersects the edge at all + if(rect.get(orient).get(HIGH) >= edge.get(LOW)) { + if(contains(rect.get(orient), edge, true)) { + //this is a closing edge + //we need to write out the intersecting rectangle and + //insert between 0 and 2 rectangles into the scanData + //write out rectangle + rectangle_type tmpRect = rect; + + if(rect.get(orient.get_perpendicular()).get(LOW) < currentCoordinate) { + //set the high coordinate perpedicular to slicing orientation + //to the current coordinate of the scan event + tmpRect.set(orient.get_perpendicular().get_direction(HIGH), + currentCoordinate); + result_type result; + assign(result, tmpRect); + rectangles.insert(rectangles.end(), result); + } + //erase the rectangle from the scan data + typename ST::iterator nextIter = dataIter; + ++nextIter; + scanData.erase(dataIter); + if(tmpRect.get(orient).get(LOW) < edge.get(LOW)) { + //insert a rectangle for the overhang of the bottom + //of the rectangle back into scan data + rectangle_type lowRect(tmpRect); + lowRect.set(orient.get_perpendicular(), interval_data<coordinate_type>(currentCoordinate, + currentCoordinate)); + lowRect.set(orient.get_direction(HIGH), edge.get(LOW)); + scanData.insert(nextIter, lowRect); + } + if(tmpRect.get(orient).get(HIGH) > edge.get(HIGH)) { + //insert a rectangle for the overhang of the top + //of the rectangle back into scan data + rectangle_type highRect(tmpRect); + highRect.set(orient.get_perpendicular(), interval_data<coordinate_type>(currentCoordinate, + currentCoordinate)); + highRect.set(orient.get_direction(LOW), edge.get(HIGH)); + scanData.insert(nextIter, highRect); + } + //we are done with this edge + edgeProcessed = true; + break; + } else { + //it must be an opening edge + //assert that rect does not overlap the edge but only touches + //write out rectangle + rectangle_type tmpRect = rect; + //set the high coordinate perpedicular to slicing orientation + //to the current coordinate of the scan event + if(tmpRect.get(orient.get_perpendicular().get_direction(LOW)) < currentCoordinate) { + tmpRect.set(orient.get_perpendicular().get_direction(HIGH), + currentCoordinate); + result_type result; + assign(result, tmpRect); + rectangles.insert(rectangles.end(), result); + } + //erase the rectangle from the scan data + typename ST::iterator nextIter = dataIter; + ++nextIter; + scanData.erase(dataIter); + dataIter = nextIter; + if(haveCurrentRect) { + if(currentRect.get(orient).get(HIGH) >= edge.get(LOW)){ + if(!edgeProcessed && currentRect.get(orient.get_direction(HIGH)) > edge.get(LOW)){ + rectangle_type tmpRect2(currentRect); + tmpRect2.set(orient.get_direction(HIGH), edge.get(LOW)); + scanData.insert(nextIter, tmpRect2); + if(currentRect.get(orient.get_direction(HIGH)) > edge.get(HIGH)) { + currentRect.set(orient, interval_data<coordinate_type>(edge.get(HIGH), currentRect.get(orient.get_direction(HIGH)))); + } else { + haveCurrentRect = false; + } + } else { + //extend the top of current rect + currentRect.set(orient.get_direction(HIGH), + (std::max)(edge.get(HIGH), + tmpRect.get(orient.get_direction(HIGH)))); + } + } else { + //insert current rect into the scanData + scanData.insert(nextIter, currentRect); + //create a new current rect + currentRect.set(orient.get_perpendicular(), interval_data<coordinate_type>(currentCoordinate, + currentCoordinate)); + currentRect.set(orient, interval_data<coordinate_type>((std::min)(tmpRect.get(orient).get(LOW), + edge.get(LOW)), + (std::max)(tmpRect.get(orient).get(HIGH), + edge.get(HIGH)))); + } + } else { + haveCurrentRect = true; + currentRect.set(orient.get_perpendicular(), interval_data<coordinate_type>(currentCoordinate, + currentCoordinate)); + currentRect.set(orient, interval_data<coordinate_type>((std::min)(tmpRect.get(orient).get(LOW), + edge.get(LOW)), + (std::max)(tmpRect.get(orient).get(HIGH), + edge.get(HIGH)))); + } + //skip to nextIter position + edgeProcessed = true; + continue; + } + //edgeProcessed = true; + } + ++dataIter; + } //end while edge intersects rectangle data + + } + if(!edgeProcessed) { + if(haveCurrentRect) { + if(currentRect.get(orient.get_perpendicular().get_direction(HIGH)) + == currentCoordinate && + currentRect.get(orient.get_direction(HIGH)) >= edge.get(LOW)) + { + if(currentRect.get(orient.get_direction(HIGH)) > edge.get(LOW)){ + rectangle_type tmpRect(currentRect); + tmpRect.set(orient.get_direction(HIGH), edge.get(LOW)); + scanData.insert(scanData.end(), tmpRect); + if(currentRect.get(orient.get_direction(HIGH)) > edge.get(HIGH)) { + currentRect.set(orient, + interval_data<coordinate_type>(edge.get(HIGH), + currentRect.get(orient.get_direction(HIGH)))); + return rectangles; + } else { + haveCurrentRect = false; + return rectangles; + } + } + //extend current rect + currentRect.set(orient.get_direction(HIGH), edge.get(HIGH)); + return rectangles; + } + scanData.insert(scanData.end(), currentRect); + haveCurrentRect = false; + } + rectangle_type tmpRect(currentRect); + tmpRect.set(orient.get_perpendicular(), interval_data<coordinate_type>(currentCoordinate, + currentCoordinate)); + tmpRect.set(orient, edge); + scanData.insert(tmpRect); + return rectangles; + } + return rectangles; + + } + + template <class T> + template <class CT> + inline + ScanLineToRects<T>& ScanLineToRects<T>::processEdge(CT& rectangles, const interval_data<coordinate_type>& edge) + { + processEdge_(rectangles, scanData_, edge, haveCurrentRect_, currentRect_, currentCoordinate_, orient_); + return *this; + } + + +} //namespace rectangle_formation + + template <typename T, typename T2> + struct get_coordinate_type_for_rectangles { + typedef typename polygon_traits<T>::coordinate_type type; + }; + template <typename T> + struct get_coordinate_type_for_rectangles<T, rectangle_concept> { + typedef typename rectangle_traits<T>::coordinate_type type; + }; + + template <typename output_container, typename iterator_type, typename rectangle_concept> + void form_rectangles(output_container& output, iterator_type begin, iterator_type end, + orientation_2d orient, rectangle_concept ) { + typedef typename output_container::value_type rectangle_type; + typedef typename get_coordinate_type_for_rectangles<rectangle_type, typename geometry_concept<rectangle_type>::type>::type Unit; + rectangle_data<Unit> model; + Unit prevPos = (std::numeric_limits<Unit>::max)(); + rectangle_formation::ScanLineToRects<rectangle_data<Unit> > scanlineToRects(orient, model); + for(iterator_type itr = begin; + itr != end; ++ itr) { + Unit pos = (*itr).first; + if(pos != prevPos) { + scanlineToRects.nextMajorCoordinate(pos); + prevPos = pos; + } + Unit lowy = (*itr).second.first; + iterator_type tmp_itr = itr; + ++itr; + Unit highy = (*itr).second.first; + scanlineToRects.processEdge(output, interval_data<Unit>(lowy, highy)); + if(abs((*itr).second.second) > 1) itr = tmp_itr; //next edge begins from this vertex + } + } +} +} +#endif + diff --git a/boost/polygon/detail/scan_arbitrary.hpp b/boost/polygon/detail/scan_arbitrary.hpp new file mode 100644 index 0000000000..1933eee7ed --- /dev/null +++ b/boost/polygon/detail/scan_arbitrary.hpp @@ -0,0 +1,2855 @@ +/* + 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_SCAN_ARBITRARY_HPP +#define BOOST_POLYGON_SCAN_ARBITRARY_HPP +#ifdef BOOST_POLYGON_DEBUG_FILE +#include <fstream> +#endif +#include "polygon_sort_adaptor.hpp" +namespace boost { namespace polygon{ + + template <typename Unit> + class line_intersection : public scanline_base<Unit> { + private: + typedef typename scanline_base<Unit>::Point Point; + + //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex + //typedef std::pair<Point, Point> half_edge; + typedef typename scanline_base<Unit>::half_edge half_edge; + + //scanline comparator functor + typedef typename scanline_base<Unit>::less_half_edge less_half_edge; + typedef typename scanline_base<Unit>::less_point less_point; + + //when parallel half edges are encounterd the set of segments is expanded + //when a edge leaves the scanline it is removed from the set + //when the set is empty the element is removed from the map + typedef int segment_id; + typedef std::pair<half_edge, std::set<segment_id> > scanline_element; + typedef std::map<half_edge, std::set<segment_id>, less_half_edge> edge_scanline; + typedef typename edge_scanline::iterator iterator; + +// std::map<Unit, std::set<segment_id> > vertical_data_; +// edge_scanline edge_scanline_; +// Unit x_; +// int just_before_; +// segment_id segment_id_; +// std::vector<std::pair<half_edge, int> > event_edges_; +// std::set<Point> intersection_queue_; + public: +// inline line_intersection() : vertical_data_(), edge_scanline_(), x_((std::numeric_limits<Unit>::max)()), just_before_(0), segment_id_(0), event_edges_(), intersection_queue_() { +// less_half_edge lessElm(&x_, &just_before_); +// edge_scanline_ = edge_scanline(lessElm); +// } +// inline line_intersection(const line_intersection& that) : vertical_data_(), edge_scanline_(), x_(), just_before_(), segment_id_(), event_edges_(), intersection_queue_() { (*this) = that; } +// inline line_intersection& operator=(const line_intersection& that) { +// x_ = that.x_; +// just_before_ = that.just_before_; +// segment_id_ = that.segment_id_; + +// //I cannot simply copy that.edge_scanline_ to this edge_scanline_ becuase the functor store pointers to other members! +// less_half_edge lessElm(&x_, &just_before_); +// edge_scanline_ = edge_scanline(lessElm); + +// edge_scanline_.insert(that.edge_scanline_.begin(), that.edge_scanline_.end()); +// return *this; +// } + +// static inline void between(Point pt, Point pt1, Point pt2) { +// less_point lp; +// if(lp(pt1, pt2)) +// return lp(pt, pt2) && lp(pt1, pt); +// return lp(pt, pt1) && lp(pt2, pt); +// } + + template <typename iT> + static inline void compute_histogram_in_y(iT begin, iT end, std::size_t size, std::vector<std::pair<Unit, std::pair<std::size_t, std::size_t> > >& histogram) { + std::vector<std::pair<Unit, int> > ends; + ends.reserve(size * 2); + for(iT itr = begin ; itr != end; ++itr) { + int count = (*itr).first.first.y() < (*itr).first.second.y() ? 1 : -1; + ends.push_back(std::make_pair((*itr).first.first.y(), count)); + ends.push_back(std::make_pair((*itr).first.second.y(), -count)); + } + gtlsort(ends.begin(), ends.end()); + histogram.reserve(ends.size()); + histogram.push_back(std::make_pair(ends.front().first, std::make_pair(0, 0))); + for(typename std::vector<std::pair<Unit, int> >::iterator itr = ends.begin(); itr != ends.end(); ++itr) { + if((*itr).first != histogram.back().first) { + histogram.push_back(std::make_pair((*itr).first, histogram.back().second)); + } + if((*itr).second < 0) + histogram.back().second.second -= (*itr).second; + histogram.back().second.first += (*itr).second; + } + } + + template <typename iT> + static inline void compute_y_cuts(std::vector<Unit>& y_cuts, iT begin, iT end, std::size_t size) { + if(begin == end) return; + if(size < 30) return; //30 is empirically chosen, but the algorithm is not sensitive to this constant + std::size_t min_cut = size; + iT cut = begin; + std::size_t position = 0; + std::size_t cut_size = 0; + std::size_t histogram_size = std::distance(begin, end); + for(iT itr = begin; itr != end; ++itr, ++position) { + if(position < histogram_size / 3) + continue; + if(histogram_size - position < histogram_size / 3) break; + if((*itr).second.first < min_cut) { + cut = itr; + min_cut = (*cut).second.first; + cut_size = position; + } + } + if(cut_size == 0 || (*cut).second.first > size / 9) //nine is empirically chosen + return; + compute_y_cuts(y_cuts, begin, cut, (*cut).second.first + (*cut).second.second); + y_cuts.push_back((*cut).first); + compute_y_cuts(y_cuts, cut, end, size - (*cut).second.second); + } + + template <typename iT> + static inline void validate_scan_divide_and_conquer(std::vector<std::set<Point> >& intersection_points, + iT begin, iT end) { + std::vector<std::pair<Unit, std::pair<std::size_t, std::size_t> > > histogram; + compute_histogram_in_y(begin, end, std::distance(begin, end), histogram); + std::vector<Unit> y_cuts; + compute_y_cuts(y_cuts, histogram.begin(), histogram.end(), std::distance(begin, end)); + std::map<Unit, std::vector<std::pair<half_edge, segment_id> > > bins; + bins[histogram.front().first] = std::vector<std::pair<half_edge, segment_id> >(); + for(typename std::vector<Unit>::iterator itr = y_cuts.begin(); itr != y_cuts.end(); ++itr) { + bins[*itr] = std::vector<std::pair<half_edge, segment_id> >(); + } + for(iT itr = begin; itr != end; ++itr) { + typename std::map<Unit, std::vector<std::pair<half_edge, segment_id> > >::iterator lb = + bins.lower_bound((std::min)((*itr).first.first.y(), (*itr).first.second.y())); + if(lb != bins.begin()) + --lb; + typename std::map<Unit, std::vector<std::pair<half_edge, segment_id> > >::iterator ub = + bins.upper_bound((std::max)((*itr).first.first.y(), (*itr).first.second.y())); + for( ; lb != ub; ++lb) { + (*lb).second.push_back(*itr); + } + } + validate_scan(intersection_points, bins[histogram.front().first].begin(), bins[histogram.front().first].end()); + for(typename std::vector<Unit>::iterator itr = y_cuts.begin(); itr != y_cuts.end(); ++itr) { + validate_scan(intersection_points, bins[*itr].begin(), bins[*itr].end(), *itr); + } + } + + template <typename iT> + static inline void validate_scan(std::vector<std::set<Point> >& intersection_points, + iT begin, iT end) { + validate_scan(intersection_points, begin, end, (std::numeric_limits<Unit>::min)()); + } + //quadratic algorithm to do same work as optimal scan for cross checking + template <typename iT> + static inline void validate_scan(std::vector<std::set<Point> >& intersection_points, + iT begin, iT end, Unit min_y) { + std::vector<Point> pts; + std::vector<std::pair<half_edge, segment_id> > data(begin, end); + for(std::size_t i = 0; i < data.size(); ++i) { + if(data[i].first.second < data[i].first.first) { + std::swap(data[i].first.first, data[i].first.second); + } + } + typename scanline_base<Unit>::compute_intersection_pack pack_; + gtlsort(data.begin(), data.end()); + //find all intersection points + for(typename std::vector<std::pair<half_edge, segment_id> >::iterator outer = data.begin(); + outer != data.end(); ++outer) { + const half_edge& he1 = (*outer).first; + //its own end points + pts.push_back(he1.first); + pts.push_back(he1.second); + std::set<Point>& segmentpts = intersection_points[(*outer).second]; + for(typename std::set<Point>::iterator itr = segmentpts.begin(); itr != segmentpts.end(); ++itr) { + if((*itr).y() > min_y - 1) + pts.push_back(*itr); + } + bool have_first_y = he1.first.y() >= min_y && he1.second.y() >= min_y; + for(typename std::vector<std::pair<half_edge, segment_id> >::iterator inner = outer; + inner != data.end(); ++inner) { + const half_edge& he2 = (*inner).first; + if(have_first_y || (he2.first.y() >= min_y && he2.second.y() >= min_y)) { + //at least one segment has a low y value within the range + if(he1 == he2) continue; + if((std::min)(he2. first.get(HORIZONTAL), + he2.second.get(HORIZONTAL)) >= + (std::max)(he1.second.get(HORIZONTAL), + he1.first.get(HORIZONTAL))) + break; + if(he1.first == he2.first || he1.second == he2.second) + continue; + Point intersection; + if(pack_.compute_intersection(intersection, he1, he2)) { + //their intersection point + pts.push_back(intersection); + intersection_points[(*inner).second].insert(intersection); + intersection_points[(*outer).second].insert(intersection); + } + } + } + } + gtlsort(pts.begin(), pts.end()); + typename std::vector<Point>::iterator newend = std::unique(pts.begin(), pts.end()); + typename std::vector<Point>::iterator lfinger = pts.begin(); + //find all segments that interact with intersection points + for(typename std::vector<std::pair<half_edge, segment_id> >::iterator outer = data.begin(); + outer != data.end(); ++outer) { + const half_edge& he1 = (*outer).first; + segment_id id1 = (*outer).second; + typedef rectangle_data<Unit> Rectangle; + //Rectangle rect1; + //set_points(rect1, he1.first, he1.second); + //typename std::vector<Point>::iterator itr = lower_bound(pts.begin(), newend, (std::min)(he1.first, he1.second)); + //typename std::vector<Point>::iterator itr2 = upper_bound(pts.begin(), newend, (std::max)(he1.first, he1.second)); + Point startpt = (std::min)(he1.first, he1.second); + Point stoppt = (std::max)(he1.first, he1.second); + //while(itr != newend && itr != pts.begin() && (*itr).get(HORIZONTAL) >= (std::min)(he1.first.get(HORIZONTAL), he1.second.get(HORIZONTAL))) --itr; + //while(itr2 != newend && (*itr2).get(HORIZONTAL) <= (std::max)(he1.first.get(HORIZONTAL), he1.second.get(HORIZONTAL))) ++itr2; + //itr = pts.begin(); + //itr2 = pts.end(); + while(lfinger != newend && (*lfinger).x() < startpt.x()) ++lfinger; + for(typename std::vector<Point>::iterator itr = lfinger ; itr != newend && (*itr).x() <= stoppt.x(); ++itr) { + if(scanline_base<Unit>::intersects_grid(*itr, he1)) + intersection_points[id1].insert(*itr); + } + } + } + + template <typename iT, typename property_type> + static inline void validate_scan(std::vector<std::pair<half_edge, std::pair<property_type, int> > >& output_segments, + iT begin, iT end) { + std::vector<std::pair<property_type, int> > input_properties; + std::vector<std::pair<half_edge, int> > input_segments, intermediate_segments; + int index = 0; + for( ; begin != end; ++begin) { + input_properties.push_back((*begin).second); + input_segments.push_back(std::make_pair((*begin).first, index++)); + } + validate_scan(intermediate_segments, input_segments.begin(), input_segments.end()); + for(std::size_t i = 0; i < intermediate_segments.size(); ++i) { + output_segments.push_back(std::make_pair(intermediate_segments[i].first, + input_properties[intermediate_segments[i].second])); + less_point lp; + if(lp(output_segments.back().first.first, output_segments.back().first.second) != + lp(input_segments[intermediate_segments[i].second].first.first, + input_segments[intermediate_segments[i].second].first.second)) { + //edge changed orientation, invert count on edge + output_segments.back().second.second *= -1; + } + if(!scanline_base<Unit>::is_vertical(input_segments[intermediate_segments[i].second].first) && + scanline_base<Unit>::is_vertical(output_segments.back().first)) { + output_segments.back().second.second *= -1; + } + if(lp(output_segments.back().first.second, output_segments.back().first.first)) { + std::swap(output_segments.back().first.first, output_segments.back().first.second); + } + } + } + + template <typename iT> + static inline void validate_scan(std::vector<std::pair<half_edge, int> >& output_segments, + iT begin, iT end) { + std::vector<std::set<Point> > intersection_points(std::distance(begin, end)); + validate_scan_divide_and_conquer(intersection_points, begin, end); + //validate_scan(intersection_points, begin, end); + segment_intersections(output_segments, intersection_points, begin, end); +// std::pair<segment_id, segment_id> offenders; +// if(!verify_scan(offenders, output_segments.begin(), output_segments.end())) { +// std::cout << "break here!\n"; +// for(typename std::set<Point>::iterator itr = intersection_points[offenders.first].begin(); +// itr != intersection_points[offenders.first].end(); ++itr) { +// std::cout << (*itr).x() << " " << (*itr).y() << " "; +// } std::cout << std::endl; +// for(typename std::set<Point>::iterator itr = intersection_points[offenders.second].begin(); +// itr != intersection_points[offenders.second].end(); ++itr) { +// std::cout << (*itr).x() << " " << (*itr).y() << " "; +// } std::cout << std::endl; +// exit(1); +// } + } + + //quadratic algorithm to find intersections + template <typename iT, typename segment_id> + static inline bool verify_scan(std::pair<segment_id, segment_id>& offenders, + iT begin, iT end) { + + std::vector<std::pair<half_edge, segment_id> > data(begin, end); + for(std::size_t i = 0; i < data.size(); ++i) { + if(data[i].first.second < data[i].first.first) { + std::swap(data[i].first.first, data[i].first.second); + } + } + gtlsort(data.begin(), data.end()); + for(typename std::vector<std::pair<half_edge, segment_id> >::iterator outer = data.begin(); + outer != data.end(); ++outer) { + const half_edge& he1 = (*outer).first; + segment_id id1 = (*outer).second; + for(typename std::vector<std::pair<half_edge, segment_id> >::iterator inner = outer; + inner != data.end(); ++inner) { + const half_edge& he2 = (*inner).first; + if(he1 == he2) continue; + if((std::min)(he2. first.get(HORIZONTAL), + he2.second.get(HORIZONTAL)) > + (std::max)(he1.second.get(HORIZONTAL), + he1.first.get(HORIZONTAL))) + break; + segment_id id2 = (*inner).second; + if(scanline_base<Unit>::intersects(he1, he2)) { + offenders.first = id1; + offenders.second = id2; + //std::cout << he1.first.x() << " " << he1.first.y() << " " << he1.second.x() << " " << he1.second.y() << " " << he2.first.x() << " " << he2.first.y() << " " << he2.second.x() << " " << he2.second.y() << std::endl; + return false; + } + } + } + return true; + } + + class less_point_down_slope : public std::binary_function<Point, Point, bool> { + public: + inline less_point_down_slope() {} + inline bool operator () (const Point& pt1, const Point& pt2) const { + if(pt1.get(HORIZONTAL) < pt2.get(HORIZONTAL)) return true; + if(pt1.get(HORIZONTAL) == pt2.get(HORIZONTAL)) { + if(pt1.get(VERTICAL) > pt2.get(VERTICAL)) return true; + } + return false; + } + }; + + template <typename iT> + static inline void segment_edge(std::vector<std::pair<half_edge, int> >& output_segments, + const half_edge& , segment_id id, iT begin, iT end) { + iT current = begin; + iT next = begin; + ++next; + while(next != end) { + output_segments.push_back(std::make_pair(half_edge(*current, *next), id)); + current = next; + ++next; + } + } + + template <typename iT> + static inline void segment_intersections(std::vector<std::pair<half_edge, int> >& output_segments, + std::vector<std::set<Point> >& intersection_points, + iT begin, iT end) { + for(iT iter = begin; iter != end; ++iter) { + //less_point lp; + const half_edge& he = (*iter).first; + //if(lp(he.first, he.second)) { + // //it is the begin event + segment_id id = (*iter).second; + const std::set<Point>& pts = intersection_points[id]; + Point hpt(he.first.get(HORIZONTAL)+1, he.first.get(VERTICAL)); + if(!scanline_base<Unit>::is_vertical(he) && scanline_base<Unit>::less_slope(he.first.get(HORIZONTAL), he.first.get(VERTICAL), + he.second, hpt)) { + //slope is below horizontal + std::vector<Point> tmpPts; + tmpPts.reserve(pts.size()); + tmpPts.insert(tmpPts.end(), pts.begin(), pts.end()); + less_point_down_slope lpds; + gtlsort(tmpPts.begin(), tmpPts.end(), lpds); + segment_edge(output_segments, he, id, tmpPts.begin(), tmpPts.end()); + } else { + segment_edge(output_segments, he, id, pts.begin(), pts.end()); + } + //} + } + } + +// //iT iterator over unsorted pair<Point> representing line segments of input +// //output_segments is populated with fully intersected output line segment half +// //edges and the index of the input segment that they are assoicated with +// //duplicate output half edges with different ids will be generated in the case +// //that parallel input segments intersection +// //outputs are in sorted order and include both begin and end events for +// //each segment +// template <typename iT> +// inline void scan(std::vector<std::pair<half_edge, int> >& output_segments, +// iT begin, iT end) { +// std::map<segment_id, std::set<Point> > intersection_points; +// scan(intersection_points, begin, end); +// segment_intersections(output_segments, intersection_points, begin, end); +// } + +// //iT iterator over sorted sequence of half edge, segment id pairs representing segment begin and end points +// //intersection points provides a mapping from input segment id (vector index) to the set +// //of intersection points assocated with that input segment +// template <typename iT> +// inline void scan(std::map<segment_id, std::set<Point> >& intersection_points, +// iT begin, iT end) { +// for(iT iter = begin; iter != end; ++iter) { +// const std::pair<half_edge, int>& elem = *iter; +// const half_edge& he = elem.first; +// Unit current_x = he.first.get(HORIZONTAL); +// if(current_x != x_) { +// process_scan_event(intersection_points); +// while(!intersection_queue_.empty() && +// (*(intersection_queue_.begin()).get(HORIZONTAL) < current_x)) { +// x_ = *(intersection_queue_.begin()).get(HORIZONTAL); +// process_intersections_at_scan_event(intersection_points); +// } +// x_ = current_x; +// } +// event_edges_.push_back(elem); +// } +// process_scan_event(intersection_points); +// } + +// inline iterator lookup(const half_edge& he) { +// return edge_scanline_.find(he); +// } + +// inline void insert_into_scanline(const half_edge& he, int id) { +// edge_scanline_[he].insert(id); +// } + +// inline void lookup_and_remove(const half_edge& he, int id) { +// iterator remove_iter = lookup(he); +// if(remove_iter == edge_scanline_.end()) { +// //std::cout << "failed to find removal segment in scanline\n"; +// return; +// } +// std::set<segment_id>& ids = (*remove_iter).second; +// std::set<segment_id>::iterator id_iter = ids.find(id); +// if(id_iter == ids.end()) { +// //std::cout << "failed to find removal segment id in scanline set\n"; +// return; +// } +// ids.erase(id_iter); +// if(ids.empty()) +// edge_scanline_.erase(remove_iter); +// } + +// static inline void update_segments(std::map<segment_id, std::set<Point> >& intersection_points, +// const std::set<segment_id>& segments, Point pt) { +// for(std::set<segment_id>::const_iterator itr = segments.begin(); itr != segments.end(); ++itr) { +// intersection_points[*itr].insert(pt); +// } +// } + +// inline void process_intersections_at_scan_event(std::map<segment_id, std::set<Point> >& intersection_points) { +// //there may be additional intersection points at this x location that haven't been +// //found yet if vertical or near vertical line segments intersect more than +// //once before the next x location +// just_before_ = true; +// std::set<iterator> intersecting_elements; +// std::set<Unit> intersection_locations; +// typedef typename std::set<Point>::iterator intersection_iterator; +// intersection_iterator iter; +// //first find all secondary intersection locations and all scanline iterators +// //that are intersecting +// for(iter = intersection_queue_.begin(); +// iter != intersection_queue_.end() && (*iter).get(HORIZONTAL) == x_; ++iter) { +// Point pt = *iter; +// Unit y = pt.get(VERTICAL); +// intersection_locations.insert(y); +// //if x_ is max there can be only end events and no sloping edges +// if(x_ != (std::numeric_limits<Unit>::max)()) { +// //deal with edges that project to the right of scanline +// //first find the edges in the scanline adjacent to primary intersectin points +// //lookup segment in scanline at pt +// iterator itr = edge_scanline_.lower_bound(half_edge(pt, Point(x_+1, y))); +// //look above pt in scanline until reaching end or segment that doesn't intersect +// //1x1 grid upper right of pt +// //look below pt in scanline until reaching begin or segment that doesn't interset +// //1x1 grid upper right of pt + +// //second find edges in scanline on the y interval of each edge found in the previous +// //step for x_ to x_ + 1 + +// //third find overlaps in the y intervals of all found edges to find all +// //secondary intersection points + +// } +// } +// //erase the intersection points from the queue +// intersection_queue_.erase(intersection_queue_.begin(), iter); +// std::vector<scanline_element> insertion_edges; +// insertion_edges.reserve(intersecting_elements.size()); +// std::vector<std::pair<Unit, iterator> > sloping_ends; +// //do all the work of updating the output of all intersecting +// for(typename std::set<iterator>::iterator inter_iter = intersecting_elements.begin(); +// inter_iter != intersecting_elements.end(); ++inter_iter) { +// //if it is horizontal update it now and continue +// if(is_horizontal((*inter_iter).first)) { +// update_segments(intersection_points, (*inter_iter).second, Point(x_, (*inter_iter).first.get(VERTICAL))); +// } else { +// //if x_ is max there can be only end events and no sloping edges +// if(x_ != (std::numeric_limits<Unit>::max)()) { +// //insert its end points into the vector of sloping ends +// const half_edge& he = (*inter_iter).first; +// Unit y = evalAtXforY(x_, he.first, he.second); +// Unit y2 = evalAtXforY(x_+1, he.first, he.second); +// if(y2 >= y) y2 +=1; //we round up, in exact case we don't worry about overbite of one +// else y += 1; //downward sloping round up +// sloping_ends.push_back(std::make_pair(y, inter_iter)); +// sloping_ends.push_back(std::make_pair(y2, inter_iter)); +// } +// } +// } + +// //merge sloping element data +// gtlsort(sloping_ends.begin(), sloping_ends.end()); +// std::map<Unit, std::set<iterator> > sloping_elements; +// std::set<iterator> merge_elements; +// for(typename std::vector<std::pair<Unit, iterator> >::iterator slop_iter = sloping_ends.begin(); +// slop_iter == sloping_ends.end(); ++slop_iter) { +// //merge into sloping elements +// typename std::set<iterator>::iterator merge_iterator = merge_elements.find((*slop_iter).second); +// if(merge_iterator == merge_elements.end()) { +// merge_elements.insert((*slop_iter).second); +// } else { +// merge_elements.erase(merge_iterator); +// } +// sloping_elements[(*slop_iter).first] = merge_elements; +// } + +// //scan intersection points +// typename std::map<Unit, std::set<segment_id> >::iterator vertical_iter = vertical_data_.begin(); +// typename std::map<Unit, std::set<iterator> >::iterator sloping_iter = sloping_elements.begin(); +// for(typename std::set<Unit>::iterator position_iter = intersection_locations.begin(); +// position_iter == intersection_locations.end(); ++position_iter) { +// //look for vertical segments that intersect this point and update them +// Unit y = *position_iter; +// Point pt(x_, y); +// //handle vertical segments +// if(vertical_iter != vertical_data_.end()) { +// typename std::map<Unit, std::set<segment_id> >::iterator next_vertical = vertical_iter; +// for(++next_vertical; next_vertical != vertical_data_.end() && +// (*next_vertical).first < y; ++next_vertical) { +// vertical_iter = next_vertical; +// } +// if((*vertical_iter).first < y && !(*vertical_iter).second.empty()) { +// update_segments(intersection_points, (*vertical_iter).second, pt); +// ++vertical_iter; +// if(vertical_iter != vertical_data_.end() && (*vertical_iter).first == y) +// update_segments(intersection_points, (*vertical_iter).second, pt); +// } +// } +// //handle sloping segments +// if(sloping_iter != sloping_elements.end()) { +// typename std::map<Unit, std::set<iterator> >::iterator next_sloping = sloping_iter; +// for(++next_sloping; next_sloping != sloping_elements.end() && +// (*next_sloping).first < y; ++next_sloping) { +// sloping_iter = next_sloping; +// } +// if((*sloping_iter).first < y && !(*sloping_iter).second.empty()) { +// for(typename std::set<iterator>::iterator element_iter = (*sloping_iter).second.begin(); +// element_iter != (*sloping_iter).second.end(); ++element_iter) { +// const half_edge& he = (*element_iter).first; +// if(intersects_grid(pt, he)) { +// update_segments(intersection_points, (*element_iter).second, pt); +// } +// } +// ++sloping_iter; +// if(sloping_iter != sloping_elements.end() && (*sloping_iter).first == y && +// !(*sloping_iter).second.empty()) { +// for(typename std::set<iterator>::iterator element_iter = (*sloping_iter).second.begin(); +// element_iter != (*sloping_iter).second.end(); ++element_iter) { +// const half_edge& he = (*element_iter).first; +// if(intersects_grid(pt, he)) { +// update_segments(intersection_points, (*element_iter).second, pt); +// } +// } +// } +// } +// } +// } + +// //erase and reinsert edges into scanline with check for future intersection +// } + +// inline void process_scan_event(std::map<segment_id, std::set<Point> >& intersection_points) { +// just_before_ = true; + +// //process end events by removing those segments from the scanline +// //and insert vertices of all events into intersection queue +// Point prev_point((std::numeric_limits<Unit>::min)(), (std::numeric_limits<Unit>::min)()); +// less_point lp; +// std::set<segment_id> vertical_ids; +// vertical_data_.clear(); +// for(std::size_t i = 0; i < event_edges_.size(); ++i) { +// segment_id id = event_edges_[i].second; +// const half_edge& he = event_edges_[i].first; +// //vertical half edges are handled during intersection processing because +// //they cannot be inserted into the scanline +// if(!is_vertical(he)) { +// if(lp(he.second, he.first)) { +// //half edge is end event +// lookup_and_remove(he, id); +// } else { +// //half edge is begin event +// insert_into_scanline(he, id); +// //note that they will be immediately removed and reinserted after +// //handling their intersection (vertex) +// //an optimization would allow them to be processed specially to avoid the redundant +// //removal and reinsertion +// } +// } else { +// //common case if you are lucky +// //update the map of y to set of segment id +// if(lp(he.second, he.first)) { +// //half edge is end event +// std::set<segment_id>::iterator itr = vertical_ids.find(id); +// if(itr == vertical_ids.end()) { +// //std::cout << "Failed to find end event id in vertical ids\n"; +// } else { +// vertical_ids.erase(itr); +// vertical_data_[he.first.get(HORIZONTAL)] = vertical_ids; +// } +// } else { +// //half edge is a begin event +// vertical_ids.insert(id); +// vertical_data_[he.first.get(HORIZONTAL)] = vertical_ids; +// } +// } +// //prevent repeated insertion of same vertex into intersection queue +// if(prev_point != he.first) +// intersection_queue_.insert(he.first); +// else +// prev_point = he.first; +// // process intersections at scan event +// process_intersections_at_scan_event(intersection_points); +// } +// event_edges_.clear(); +// } + + public: + template <typename stream_type> + static inline bool test_validate_scan(stream_type& stdcout) { + std::vector<std::pair<half_edge, segment_id> > input, edges; + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), 0)); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 10)), 1)); + std::pair<segment_id, segment_id> result; + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail1 " << result.first << " " << result.second << "\n"; + return false; + } + input.push_back(std::make_pair(half_edge(Point(0, 5), Point(5, 5)), 2)); + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 " << result.first << " " << result.second << "\n"; + return false; + } + input.pop_back(); + input.push_back(std::make_pair(half_edge(Point(1, 0), Point(11, 11)), input.size())); + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail3 " << result.first << " " << result.second << "\n"; + return false; + } + input.push_back(std::make_pair(half_edge(Point(1, 0), Point(10, 11)), input.size())); + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail4 " << result.first << " " << result.second << "\n"; + return false; + } + input.pop_back(); + input.push_back(std::make_pair(half_edge(Point(1, 2), Point(11, 11)), input.size())); + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail5 " << result.first << " " << result.second << "\n"; + return false; + } + input.push_back(std::make_pair(half_edge(Point(0, 5), Point(0, 11)), input.size())); + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail6 " << result.first << " " << result.second << "\n"; + return false; + } + input.pop_back(); + for(std::size_t i = 0; i < input.size(); ++i) { + std::swap(input[i].first.first, input[i].first.second); + } + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail5 2 " << result.first << " " << result.second << "\n"; + return false; + } + for(std::size_t i = 0; i < input.size(); ++i) { + input[i].first.first = Point(input[i].first.first.get(HORIZONTAL) * -1, + input[i].first.first.get(VERTICAL) * -1); + input[i].first.second = Point(input[i].first.second.get(HORIZONTAL) * -1, + input[i].first.second.get(VERTICAL) * -1); + } + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + stdcout << edges.size() << std::endl; + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail5 3 " << result.first << " " << result.second << "\n"; + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(5, 7), Point(7, 6)), 0)); + input.push_back(std::make_pair(half_edge(Point(2, 4), Point(6, 7)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 1 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(3, 2), Point(1, 7)), 0)); + input.push_back(std::make_pair(half_edge(Point(0, 6), Point(7, 4)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 2 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(6, 6), Point(1, 0)), 0)); + input.push_back(std::make_pair(half_edge(Point(3, 6), Point(2, 3)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 3 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(7, 0)), 0)); + input.push_back(std::make_pair(half_edge(Point(6, 0), Point(2, 0)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 4 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(-17333131 - -17208131, -10316869 - -10191869), Point(0, 0)), 0)); + input.push_back(std::make_pair(half_edge(Point(-17291260 - -17208131, -10200000 - -10191869), Point(-17075000 - -17208131, -10200000 - -10191869)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 5 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(-17333131, -10316869), Point(-17208131, -10191869)), 0)); + input.push_back(std::make_pair(half_edge(Point(-17291260, -10200000), Point(-17075000, -10200000)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 6 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(-9850009+9853379, -286971+290340), Point(-12777869+9853379, -3214831+290340)), 0)); + input.push_back(std::make_pair(half_edge(Point(-5223510+9853379, -290340+290340), Point(-9858140+9853379, -290340+290340)), 1)); + validate_scan(edges, input.begin(), input.end()); + print(edges); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 7 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(-9850009, -286971), Point(-12777869, -3214831)), 0)); + input.push_back(std::make_pair(half_edge(Point(-5223510, -290340), Point(-9858140, -290340)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 8 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + //3 3 2 2: 0; 4 2 0 6: 1; 0 3 6 3: 2; 4 1 5 5: 3; + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(3, 3), Point(2, 2)), 0)); + input.push_back(std::make_pair(half_edge(Point(4, 2), Point(0, 6)), 1)); + input.push_back(std::make_pair(half_edge(Point(0, 3), Point(6, 3)), 2)); + input.push_back(std::make_pair(half_edge(Point(4, 1), Point(5, 5)), 3)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail4 1 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + //5 7 1 3: 0; 4 5 2 1: 1; 2 5 2 1: 2; 4 1 5 3: 3; + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(5, 7), Point(1, 3)), 0)); + input.push_back(std::make_pair(half_edge(Point(4, 5), Point(2, 1)), 1)); + input.push_back(std::make_pair(half_edge(Point(2, 5), Point(2, 1)), 2)); + input.push_back(std::make_pair(half_edge(Point(4, 1), Point(5, 3)), 3)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail4 2 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + //1 0 -4 -1: 0; 0 0 2 -1: 1; + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(1, 0), Point(-4, -1)), 0)); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(2, -1)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 5 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + Unit min_c =0; + Unit max_c =0; + for(unsigned int outer = 0; outer < 1000; ++outer) { + input.clear(); + for(unsigned int i = 0; i < 4; ++i) { + Unit x1 = rand(); + Unit x2 = rand(); + Unit y1 = rand(); + Unit y2 = rand(); + int neg1 = rand() % 2; + if(neg1) x1 *= -1; + int neg2 = rand() % 2; + if(neg2) x2 *= -1; + int neg3 = rand() % 2; + if(neg3) y1 *= -1; + int neg4 = rand() % 2; + if(neg4) y2 *= -1; + if(x1 < min_c) min_c = x1; + if(x2 < min_c) min_c = x2; + if(y1 < min_c) min_c = y1; + if(y2 < min_c) min_c = y2; + if(x1 > max_c) max_c = x1; + if(x2 > max_c) max_c = x2; + if(y1 > max_c) max_c = y1; + if(y2 > max_c) max_c = y2; + Point pt1(x1, y1); + Point pt2(x2, y2); + if(pt1 != pt2) + input.push_back(std::make_pair(half_edge(pt1, pt2), i)); + } + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail9 " << outer << ": " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + } + return true; + } + + //static void print(const std::pair<half_edge, segment_id>& segment) { + //std::cout << segment.first.first << " " << segment.first.second << ": " << segment.second << "; "; + //} + static void print(const std::vector<std::pair<half_edge, segment_id> >& vec) { + for(std::size_t i = 0; i < vec.size(); ++ i) { + // print(vec[i]); + } + //std::cout << std::endl; + } + + template <typename stream_type> + static inline bool test_verify_scan(stream_type& stdcout) { + std::vector<std::pair<half_edge, segment_id> > edges; + edges.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), 0)); + edges.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 10)), 1)); + std::pair<segment_id, segment_id> result; + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail1\n"; + return false; + } + edges.push_back(std::make_pair(half_edge(Point(0, 5), Point(5, 5)), 2)); + if(verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail2\n"; + return false; + } + edges.pop_back(); + edges.push_back(std::make_pair(half_edge(Point(1, 0), Point(11, 11)), (segment_id)edges.size())); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail3\n"; + return false; + } + edges.push_back(std::make_pair(half_edge(Point(1, 0), Point(10, 11)), (segment_id)edges.size())); + if(verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail4\n"; + return false; + } + edges.pop_back(); + edges.push_back(std::make_pair(half_edge(Point(1, 2), Point(11, 11)), (segment_id)edges.size())); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail5 " << result.first << " " << result.second << "\n"; + return false; + } + edges.push_back(std::make_pair(half_edge(Point(0, 5), Point(0, 11)), (segment_id)edges.size())); + if(verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail6 " << result.first << " " << result.second << "\n"; + return false; + } + edges.pop_back(); + for(std::size_t i = 0; i < edges.size(); ++i) { + std::swap(edges[i].first.first, edges[i].first.second); + } + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail5 2 " << result.first << " " << result.second << "\n"; + return false; + } + for(std::size_t i = 0; i < edges.size(); ++i) { + edges[i].first.first = Point(edges[i].first.first.get(HORIZONTAL) * -1, + edges[i].first.first.get(VERTICAL) * -1); + edges[i].first.second = Point(edges[i].first.second.get(HORIZONTAL) * -1, + edges[i].first.second.get(VERTICAL) * -1); + } + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail5 3 " << result.first << " " << result.second << "\n"; + return false; + } + return true; + } + + }; + + //scanline consumes the "flattened" fully intersected line segments produced by + //a pass of line_intersection along with property and count information and performs a + //useful operation like booleans or property merge or connectivity extraction + template <typename Unit, typename property_type, typename keytype = std::set<property_type> > + class scanline : public scanline_base<Unit> { + public: + //definitions + typedef typename scanline_base<Unit>::Point Point; + + //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex + //typedef std::pair<Point, Point> half_edge; + typedef typename scanline_base<Unit>::half_edge half_edge; + + //scanline comparator functor + typedef typename scanline_base<Unit>::less_half_edge less_half_edge; + typedef typename scanline_base<Unit>::less_point less_point; + + typedef keytype property_set; + //this is the data type used internally to store the combination of property counts at a given location + typedef std::vector<std::pair<property_type, int> > property_map; + //this data structure assocates a property and count to a half edge + typedef std::pair<half_edge, std::pair<property_type, int> > vertex_property; + //this data type is used internally to store the combined property data for a given half edge + typedef std::pair<half_edge, property_map> vertex_data; + //this data type stores the combination of many half edges + typedef std::vector<vertex_property> property_merge_data; + //this data structure stores end points of edges in the scanline + typedef std::set<Point, less_point> end_point_queue; + + //this is the output data type that is created by the scanline before it is post processed based on content of property sets + typedef std::pair<half_edge, std::pair<property_set, property_set> > half_edge_property; + + //this is the scanline data structure + typedef std::map<half_edge, property_map, less_half_edge> scanline_type; + typedef std::pair<half_edge, property_map> scanline_element; + typedef typename scanline_type::iterator iterator; + typedef typename scanline_type::const_iterator const_iterator; + + //data + scanline_type scan_data_; + std::vector<iterator> removal_set_; //edges to be removed at the current scanline stop + std::vector<scanline_element> insertion_set_; //edge to be inserted after current scanline stop + end_point_queue end_point_queue_; + Unit x_; + Unit y_; + int just_before_; + typename scanline_base<Unit>::evalAtXforYPack evalAtXforYPack_; + public: + inline scanline() : scan_data_(), removal_set_(), insertion_set_(), end_point_queue_(), + x_((std::numeric_limits<Unit>::max)()), y_((std::numeric_limits<Unit>::max)()), just_before_(false), evalAtXforYPack_() { + less_half_edge lessElm(&x_, &just_before_, &evalAtXforYPack_); + scan_data_ = scanline_type(lessElm); + } + inline scanline(const scanline& that) : scan_data_(), removal_set_(), insertion_set_(), end_point_queue_(), + x_((std::numeric_limits<Unit>::max)()), y_((std::numeric_limits<Unit>::max)()), just_before_(false), evalAtXforYPack_() { + (*this) = that; } + inline scanline& operator=(const scanline& that) { + x_ = that.x_; + y_ = that.y_; + just_before_ = that.just_before_; + end_point_queue_ = that.end_point_queue_; + //I cannot simply copy that.scanline_type to this scanline_type becuase the functor store pointers to other members! + less_half_edge lessElm(&x_, &just_before_); + scan_data_ = scanline_type(lessElm); + + scan_data_.insert(that.scan_data_.begin(), that.scan_data_.end()); + return *this; + } + + template <typename result_type, typename result_functor> + void write_out(result_type& result, result_functor rf, const half_edge& he, + const property_map& pm_left, const property_map& pm_right) { + //std::cout << "write out "; + //std::cout << he.first << ", " << he.second << std::endl; + property_set ps_left, ps_right; + set_unique_property(ps_left, pm_left); + set_unique_property(ps_right, pm_right); + if(ps_left != ps_right) { + //std::cout << "!equivalent\n"; + rf(result, he, ps_left, ps_right); + } + } + + template <typename result_type, typename result_functor, typename iT> + iT handle_input_events(result_type& result, result_functor rf, iT begin, iT end) { + typedef typename high_precision_type<Unit>::type high_precision; + //for each event + property_map vertical_properties_above; + property_map vertical_properties_below; + half_edge vertical_edge_above; + half_edge vertical_edge_below; + std::vector<scanline_element> insertion_elements; + //current_iter should increase monotonically toward end as we process scanline stop + iterator current_iter = scan_data_.begin(); + just_before_ = true; + Unit y = (std::numeric_limits<Unit>::min)(); + bool first_iteration = true; + //we want to return from inside the loop when we hit end or new x +#ifdef BOOST_POLYGON_MSVC +#pragma warning( disable: 4127 ) +#endif + while(true) { + if(begin == end || (!first_iteration && ((*begin).first.first.get(VERTICAL) != y || + (*begin).first.first.get(HORIZONTAL) != x_))) { + //lookup iterator range in scanline for elements coming in from the left + //that end at this y + Point pt(x_, y); + //grab the properties coming in from below + property_map properties_below; + if(current_iter != scan_data_.end()) { + //make sure we are looking at element in scanline just below y + //if(evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) != y) { + if(scanline_base<Unit>::on_above_or_below(Point(x_, y), (*current_iter).first) != 0) { + Point e2(pt); + if(e2.get(VERTICAL) != (std::numeric_limits<Unit>::max)()) + e2.set(VERTICAL, e2.get(VERTICAL) + 1); + else + e2.set(VERTICAL, e2.get(VERTICAL) - 1); + half_edge vhe(pt, e2); + current_iter = scan_data_.lower_bound(vhe); + } + if(current_iter != scan_data_.end()) { + //get the bottom iterator for elements at this point + //while(evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) >= (high_precision)y && + while(scanline_base<Unit>::on_above_or_below(Point(x_, y), (*current_iter).first) != 1 && + current_iter != scan_data_.begin()) { + --current_iter; + } + //if(evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) >= (high_precision)y) { + if(scanline_base<Unit>::on_above_or_below(Point(x_, y), (*current_iter).first) != 1) { + properties_below.clear(); + } else { + properties_below = (*current_iter).second; + //move back up to y or one past y + ++current_iter; + } + } + } + std::vector<iterator> edges_from_left; + while(current_iter != scan_data_.end() && + //can only be true if y is integer + //evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) == y) { + scanline_base<Unit>::on_above_or_below(Point(x_, y), (*current_iter).first) == 0) { + //removal_set_.push_back(current_iter); + ++current_iter; + } + //merge vertical count with count from below + if(!vertical_properties_below.empty()) { + merge_property_maps(vertical_properties_below, properties_below); + //write out vertical edge + write_out(result, rf, vertical_edge_below, properties_below, vertical_properties_below); + } else { + merge_property_maps(vertical_properties_below, properties_below); + } + //iteratively add intertion element counts to count from below + //and write them to insertion set + for(std::size_t i = 0; i < insertion_elements.size(); ++i) { + if(i == 0) { + merge_property_maps(insertion_elements[i].second, vertical_properties_below); + write_out(result, rf, insertion_elements[i].first, insertion_elements[i].second, vertical_properties_below); + } else { + merge_property_maps(insertion_elements[i].second, insertion_elements[i-1].second); + write_out(result, rf, insertion_elements[i].first, insertion_elements[i].second, insertion_elements[i-1].second); + } + insertion_set_.push_back(insertion_elements[i]); + } + if((begin == end || (*begin).first.first.get(HORIZONTAL) != x_)) { + if(vertical_properties_above.empty()) { + return begin; + } else { + y = vertical_edge_above.second.get(VERTICAL); + vertical_properties_below.clear(); + vertical_properties_above.swap(vertical_properties_below); + vertical_edge_below = vertical_edge_above; + insertion_elements.clear(); + continue; + } + } + vertical_properties_below.clear(); + vertical_properties_above.swap(vertical_properties_below); + vertical_edge_below = vertical_edge_above; + insertion_elements.clear(); + } + if(begin != end) { + const vertex_property& vp = *begin; + const half_edge& he = vp.first; + y = he.first.get(VERTICAL); + first_iteration = false; + if(! vertical_properties_below.empty() && + vertical_edge_below.second.get(VERTICAL) < y) { + y = vertical_edge_below.second.get(VERTICAL); + continue; + } + if(scanline_base<Unit>::is_vertical(he)) { + update_property_map(vertical_properties_above, vp.second); + vertical_edge_above = he; + } else { + if(insertion_elements.empty() || + insertion_elements.back().first != he) { + insertion_elements.push_back(scanline_element(he, property_map())); + } + update_property_map(insertion_elements.back().second, vp.second); + } + ++begin; + } + } +#ifdef BOOST_POLYGON_MSVC +#pragma warning( default: 4127 ) +#endif + + } + + inline void erase_end_events(typename end_point_queue::iterator epqi) { + end_point_queue_.erase(end_point_queue_.begin(), epqi); + for(typename std::vector<iterator>::iterator retire_itr = removal_set_.begin(); + retire_itr != removal_set_.end(); ++retire_itr) { + scan_data_.erase(*retire_itr); + } + removal_set_.clear(); + } + + + inline void remove_retired_edges_from_scanline() { + just_before_ = true; + typename end_point_queue::iterator epqi = end_point_queue_.begin(); + Unit current_x = x_; + Unit previous_x = x_; + while(epqi != end_point_queue_.end() && + (*epqi).get(HORIZONTAL) <= current_x) { + x_ = (*epqi).get(HORIZONTAL); + if(x_ != previous_x) erase_end_events(epqi); + previous_x = x_; + //lookup elements + Point e2(*epqi); + if(e2.get(VERTICAL) != (std::numeric_limits<Unit>::max)()) + e2.set(VERTICAL, e2.get(VERTICAL) + 1); + else + e2.set(VERTICAL, e2.get(VERTICAL) - 1); + half_edge vhe_e(*epqi, e2); + iterator current_iter = scan_data_.lower_bound(vhe_e); + while(current_iter != scan_data_.end() && (*current_iter).first.second == (*epqi)) { + //evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) == (*epqi).get(VERTICAL)) { + removal_set_.push_back(current_iter); + ++current_iter; + } + ++epqi; + } + x_ = current_x; + erase_end_events(epqi); + } + + inline void insert_new_edges_into_scanline() { + just_before_ = false; + for(typename std::vector<scanline_element>::iterator insert_itr = insertion_set_.begin(); + insert_itr != insertion_set_.end(); ++insert_itr) { + scan_data_.insert(*insert_itr); + end_point_queue_.insert((*insert_itr).first.second); + } + insertion_set_.clear(); + } + + //iterator over range of vertex property elements and call result functor + //passing edge to be output, the merged data on both sides and the result + template <typename result_type, typename result_functor, typename iT> + void scan(result_type& result, result_functor rf, iT begin, iT end) { + while(begin != end) { + x_ = (*begin).first.first.get(HORIZONTAL); //update scanline stop location + //print_scanline(); + --x_; + remove_retired_edges_from_scanline(); + ++x_; + begin = handle_input_events(result, rf, begin, end); + remove_retired_edges_from_scanline(); + //print_scanline(); + insert_new_edges_into_scanline(); + } + //print_scanline(); + x_ = (std::numeric_limits<Unit>::max)(); + remove_retired_edges_from_scanline(); + } + + //inline void print_scanline() { + // std::cout << "scanline at " << x_ << ": "; + // for(iterator itr = scan_data_.begin(); itr != scan_data_.end(); ++itr) { + // const scanline_element& se = *itr; + // const half_edge& he = se.first; + // const property_map& mp = se.second; + // std::cout << he.first << ", " << he.second << " ( "; + // for(std::size_t i = 0; i < mp.size(); ++i) { + // std::cout << mp[i].first << ":" << mp[i].second << " "; + // } std::cout << ") "; + // } std::cout << std::endl; + //} + + static inline void merge_property_maps(property_map& mp, const property_map& mp2) { + property_map newmp; + newmp.reserve(mp.size() + mp2.size()); + unsigned int i = 0; + unsigned int j = 0; + while(i != mp.size() && j != mp2.size()) { + if(mp[i].first < mp2[j].first) { + newmp.push_back(mp[i]); + ++i; + } else if(mp[i].first > mp2[j].first) { + newmp.push_back(mp2[j]); + ++j; + } else { + int count = mp[i].second; + count += mp2[j].second; + if(count) { + newmp.push_back(mp[i]); + newmp.back().second = count; + } + ++i; + ++j; + } + } + while(i != mp.size()) { + newmp.push_back(mp[i]); + ++i; + } + while(j != mp2.size()) { + newmp.push_back(mp2[j]); + ++j; + } + mp.swap(newmp); + } + + static inline void update_property_map(property_map& mp, const std::pair<property_type, int>& prop_data) { + property_map newmp; + newmp.reserve(mp.size() +1); + bool consumed = false; + for(std::size_t i = 0; i < mp.size(); ++i) { + if(!consumed && prop_data.first == mp[i].first) { + consumed = true; + int count = prop_data.second + mp[i].second; + if(count) + newmp.push_back(std::make_pair(prop_data.first, count)); + } else if(!consumed && prop_data.first < mp[i].first) { + consumed = true; + newmp.push_back(prop_data); + newmp.push_back(mp[i]); + } else { + newmp.push_back(mp[i]); + } + } + if(!consumed) newmp.push_back(prop_data); + mp.swap(newmp); + } + + static inline void set_unique_property(property_set& unqiue_property, const property_map& property) { + unqiue_property.clear(); + for(typename property_map::const_iterator itr = property.begin(); itr != property.end(); ++itr) { + if((*itr).second > 0) + unqiue_property.insert(unqiue_property.end(), (*itr).first); + } + } + + static inline bool common_vertex(const half_edge& he1, const half_edge& he2) { + return he1.first == he2.first || + he1.first == he2.second || + he1.second == he2.first || + he1.second == he2.second; + } + + typedef typename scanline_base<Unit>::vertex_half_edge vertex_half_edge; + template <typename iT> + static inline void convert_segments_to_vertex_half_edges(std::vector<vertex_half_edge>& output, iT begin, iT end) { + for( ; begin != end; ++begin) { + const half_edge& he = (*begin).first; + int count = (*begin).second; + output.push_back(vertex_half_edge(he.first, he.second, count)); + output.push_back(vertex_half_edge(he.second, he.first, -count)); + } + gtlsort(output.begin(), output.end()); + } + + class test_functor { + public: + inline test_functor() {} + inline void operator()(std::vector<std::pair<half_edge, std::pair<property_set, property_set> > >& result, + const half_edge& he, const property_set& ps_left, const property_set& ps_right) { + result.push_back(std::make_pair(he, std::make_pair(ps_left, ps_right))); + } + }; + template <typename stream_type> + static inline bool test_scanline(stream_type& stdcout) { + std::vector<std::pair<half_edge, std::pair<property_set, property_set> > > result; + std::vector<std::pair<half_edge, std::pair<property_type, int> > > input; + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(10, 10)), std::make_pair(0, -1))); + scanline sl; + test_functor tf; + sl.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + input.clear(); + result.clear(); + input.push_back(std::make_pair(half_edge(Point(-1, -1), Point(10, 0)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(-1, -1), Point(0, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(11, 11)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(11, 11)), std::make_pair(0, 1))); + scanline sl2; + sl2.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + input.clear(); + result.clear(); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(1, 1), Point(8, 2)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(1, 1), Point(2, 8)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(2, 8), Point(9, 9)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(8, 2), Point(9, 9)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(10, 10)), std::make_pair(0, -1))); + scanline sl3; + sl3.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + input.clear(); + result.clear(); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(1, 1), Point(8, 2)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(1, 1), Point(2, 8)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(2, 8), Point(9, 9)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(8, 2), Point(9, 9)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(10, 10)), std::make_pair(0, -1))); + scanline sl4; + sl4.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + input.clear(); + result.clear(); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(9, 1)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(1, 9)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(1, 9), Point(10, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(9, 1), Point(10, 10)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(10, 10)), std::make_pair(0, -1))); + scanline sl5; + sl5.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + input.clear(); + result.clear(); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(9, 1)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(1, 9)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(1, 9), Point(10, 10)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(9, 1), Point(10, 10)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(10, 10)), std::make_pair(0, -1))); + scanline sl6; + sl6.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + input.clear(); + result.clear(); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(9, 1)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(1, 9)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(0, 20), Point(10, 20)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 20), Point(9, 21)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 20), Point(1, 29)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(0, 20), Point(0, 30)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 30), Point(10, 30)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(1, 9), Point(10, 10)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(1, 29), Point(10, 30)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(9, 1), Point(10, 10)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(9, 21), Point(10, 30)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(10, 20), Point(10, 30)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(10, 20), Point(10, 30)), std::make_pair(0, -1))); + scanline sl7; + sl7.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + input.clear(); + result.clear(); + input.push_back(std::make_pair(half_edge(Point(-1, -1), Point(10, 0)), std::make_pair(0, 1))); //a + input.push_back(std::make_pair(half_edge(Point(-1, -1), Point(0, 10)), std::make_pair(0, -1))); //a + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(11, 11)), std::make_pair(0, -1))); //a + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(20, 0)), std::make_pair(0, 1))); //b + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(11, 11)), std::make_pair(0, -1))); //b + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(11, 11)), std::make_pair(0, 1))); //a + input.push_back(std::make_pair(half_edge(Point(11, 11), Point(20, 10)), std::make_pair(0, -1))); //b + input.push_back(std::make_pair(half_edge(Point(20, 0), Point(30, 0)), std::make_pair(0, 1))); //c + input.push_back(std::make_pair(half_edge(Point(20, 0), Point(20, 10)), std::make_pair(0, -1))); //b + input.push_back(std::make_pair(half_edge(Point(20, 0), Point(20, 10)), std::make_pair(0, 1))); //c + input.push_back(std::make_pair(half_edge(Point(20, 10), Point(30, 10)), std::make_pair(0, -1))); //c + input.push_back(std::make_pair(half_edge(Point(30, 0), Point(30, 10)), std::make_pair(0, -1))); //c + scanline sl8; + sl8.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + return true; + } + + }; + + template <typename Unit> + class merge_output_functor { + public: + typedef typename scanline_base<Unit>::half_edge half_edge; + merge_output_functor() {} + template <typename result_type, typename key_type> + void operator()(result_type& result, const half_edge& edge, const key_type& left, const key_type& right) { + typename std::pair<half_edge, int> elem; + elem.first = edge; + elem.second = 1; + if(edge.second < edge.first) elem.second *= -1; + if(scanline_base<Unit>::is_vertical(edge)) elem.second *= -1; + if(!left.empty()) + result[left].insert_clean(elem); + elem.second *= -1; + if(!right.empty()) + result[right].insert_clean(elem); + } + }; + + template <typename Unit, typename property_type, typename key_type = std::set<property_type>, + typename output_functor_type = merge_output_functor<Unit> > + class property_merge : public scanline_base<Unit> { + protected: + typedef typename scanline_base<Unit>::Point Point; + + //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex + //typedef std::pair<Point, Point> half_edge; + typedef typename scanline_base<Unit>::half_edge half_edge; + + //scanline comparator functor + typedef typename scanline_base<Unit>::less_half_edge less_half_edge; + typedef typename scanline_base<Unit>::less_point less_point; + + //this data structure assocates a property and count to a half edge + typedef std::pair<half_edge, std::pair<property_type, int> > vertex_property; + //this data type stores the combination of many half edges + typedef std::vector<vertex_property> property_merge_data; + + //this is the data type used internally to store the combination of property counts at a given location + typedef std::vector<std::pair<property_type, int> > property_map; + //this data type is used internally to store the combined property data for a given half edge + typedef std::pair<half_edge, property_map> vertex_data; + + property_merge_data pmd; + typename scanline_base<Unit>::evalAtXforYPack evalAtXforYPack_; + + template<typename vertex_data_type> + class less_vertex_data { + typename scanline_base<Unit>::evalAtXforYPack* pack_; + public: + less_vertex_data() : pack_() {} + less_vertex_data(typename scanline_base<Unit>::evalAtXforYPack* pack) : pack_(pack) {} + bool operator() (const vertex_data_type& lvalue, const vertex_data_type& rvalue) const { + less_point lp; + if(lp(lvalue.first.first, rvalue.first.first)) return true; + if(lp(rvalue.first.first, lvalue.first.first)) return false; + Unit x = lvalue.first.first.get(HORIZONTAL); + int just_before_ = 0; + less_half_edge lhe(&x, &just_before_, pack_); + return lhe(lvalue.first, rvalue.first); + } + }; + + + inline void sort_property_merge_data() { + less_vertex_data<vertex_property> lvd(&evalAtXforYPack_); + gtlsort(pmd.begin(), pmd.end(), lvd); + } + public: + inline property_merge_data& get_property_merge_data() { return pmd; } + inline property_merge() : pmd(), evalAtXforYPack_() {} + inline property_merge(const property_merge& pm) : pmd(pm.pmd), evalAtXforYPack_(pm.evalAtXforYPack_) {} + inline property_merge& operator=(const property_merge& pm) { pmd = pm.pmd; return *this; } + + template <typename polygon_type> + void insert(const polygon_type& polygon_object, const property_type& property_value, bool is_hole = false) { + insert(polygon_object, property_value, is_hole, typename geometry_concept<polygon_type>::type()); + } + + //result type should be std::map<std::set<property_type>, polygon_set_type> + //or std::map<std::vector<property_type>, polygon_set_type> + template <typename result_type> + void merge(result_type& result) { + if(pmd.empty()) return; + //intersect data + property_merge_data tmp_pmd; + line_intersection<Unit>::validate_scan(tmp_pmd, pmd.begin(), pmd.end()); + pmd.swap(tmp_pmd); + sort_property_merge_data(); + scanline<Unit, property_type, key_type> sl; + output_functor_type mof; + sl.scan(result, mof, pmd.begin(), pmd.end()); + } + + inline bool verify1() { + std::pair<int, int> offenders; + std::vector<std::pair<half_edge, int> > lines; + int count = 0; + for(std::size_t i = 0; i < pmd.size(); ++i) { + lines.push_back(std::make_pair(pmd[i].first, count++)); + } + if(!line_intersection<Unit>::verify_scan(offenders, lines.begin(), lines.end())) { + //stdcout << "Intersection failed!\n"; + //stdcout << offenders.first << " " << offenders.second << std::endl; + return false; + } + std::vector<Point> pts; + for(std::size_t i = 0; i < lines.size(); ++i) { + pts.push_back(lines[i].first.first); + pts.push_back(lines[i].first.second); + } + gtlsort(pts.begin(), pts.end()); + for(std::size_t i = 0; i < pts.size(); i+=2) { + if(pts[i] != pts[i+1]) { + //stdcout << "Non-closed figures after line intersection!\n"; + return false; + } + } + return true; + } + + void clear() {*this = property_merge();} + + protected: + template <typename polygon_type> + void insert(const polygon_type& polygon_object, const property_type& property_value, bool is_hole, + polygon_concept ) { + bool first_iteration = true; + bool second_iteration = true; + Point first_point; + Point second_point; + Point previous_previous_point; + Point previous_point; + Point current_point; + direction_1d winding_dir = winding(polygon_object); + for(typename polygon_traits<polygon_type>::iterator_type itr = begin_points(polygon_object); + itr != end_points(polygon_object); ++itr) { + assign(current_point, *itr); + if(first_iteration) { + first_iteration = false; + first_point = previous_point = current_point; + } else if(second_iteration) { + if(previous_point != current_point) { + second_iteration = false; + previous_previous_point = previous_point; + second_point = previous_point = current_point; + } + } else { + if(previous_point != current_point) { + create_vertex(pmd, previous_point, current_point, winding_dir, + is_hole, property_value); + previous_previous_point = previous_point; + previous_point = current_point; + } + } + } + current_point = first_point; + if(!first_iteration && !second_iteration) { + if(previous_point != current_point) { + create_vertex(pmd, previous_point, current_point, winding_dir, + is_hole, property_value); + previous_previous_point = previous_point; + previous_point = current_point; + } + current_point = second_point; + create_vertex(pmd, previous_point, current_point, winding_dir, + is_hole, property_value); + previous_previous_point = previous_point; + previous_point = current_point; + } + } + + template <typename polygon_with_holes_type> + void insert(const polygon_with_holes_type& polygon_with_holes_object, const property_type& property_value, bool is_hole, + polygon_with_holes_concept tag) { + insert(polygon_with_holes_object, property_value, is_hole, polygon_concept()); + for(typename polygon_with_holes_traits<polygon_with_holes_type>::iterator_holes_type itr = + begin_holes(polygon_with_holes_object); + itr != end_holes(polygon_with_holes_object); ++itr) { + insert(*itr, property_value, !is_hole, polygon_concept()); + } + } + + template <typename rectangle_type> + void insert(const rectangle_type& rectangle_object, const property_type& property_value, bool is_hole, + rectangle_concept ) { + polygon_90_data<Unit> poly; + assign(poly, rectangle_object); + insert(poly, property_value, is_hole, polygon_concept()); + } + + public: //change to private when done testing + + static inline void create_vertex(property_merge_data& pmd, + const Point& current_point, + const Point& next_point, + direction_1d winding, + bool is_hole, const property_type& property) { + if(current_point == next_point) return; + vertex_property current_vertex; + current_vertex.first.first = current_point; + current_vertex.first.second = next_point; + current_vertex.second.first = property; + int multiplier = 1; + if(winding == CLOCKWISE) + multiplier = -1; + if(is_hole) + multiplier *= -1; + if(current_point < next_point) { + multiplier *= -1; + std::swap(current_vertex.first.first, current_vertex.first.second); + } + current_vertex.second.second = multiplier * (euclidean_distance(next_point, current_point, HORIZONTAL) == 0 ? -1: 1); + pmd.push_back(current_vertex); + //current_vertex.first.second = previous_point; + //current_vertex.second.second *= -1; + //pmd.push_back(current_vertex); + } + + static inline void sort_vertex_half_edges(vertex_data& vertex) { + less_half_edge_pair lessF(vertex.first); + gtlsort(vertex.second.begin(), vertex.second.end(), lessF); + } + + class less_half_edge_pair { + private: + Point pt_; + public: + less_half_edge_pair(const Point& pt) : pt_(pt) {} + bool operator()(const half_edge& e1, const half_edge& e2) { + const Point& pt1 = e1.first; + const Point& pt2 = e2.first; + if(get(pt1, HORIZONTAL) == + get(pt_, HORIZONTAL)) { + //vertical edge is always largest + return false; + } + if(get(pt2, HORIZONTAL) == + get(pt_, HORIZONTAL)) { + //if half edge 1 is not vertical its slope is less than that of half edge 2 + return get(pt1, HORIZONTAL) != get(pt2, HORIZONTAL); + } + return scanline_base<Unit>::less_slope(get(pt_, HORIZONTAL), + get(pt_, VERTICAL), pt1, pt2); + } + }; + + public: + //test functions + template <typename stream_type> + static stream_type& print (stream_type& o, const property_map& c) + { + o << "count: {"; + for(typename property_map::const_iterator itr = c.begin(); itr != c.end(); ++itr) { + o << ((*itr).first) << ":" << ((*itr).second) << " "; + } + return o << "} "; + } + + + template <typename stream_type> + static stream_type& print (stream_type& o, const half_edge& he) + { + o << "half edge: ("; + o << (he.first); + return o << ", " << (he.second) << ") "; + } + + template <typename stream_type> + static stream_type& print (stream_type& o, const vertex_property& c) + { + o << "vertex property: {"; + print(o, c.first); + o << ", " << c.second.first << ":" << c.second.second << " "; + return o; + } + + template <typename stream_type> + static stream_type& print (stream_type& o, const std::vector<vertex_property>& hev) + { + o << "vertex properties: {"; + for(std::size_t i = 0; i < hev.size(); ++i) { + print(o, (hev[i])) << " "; + } + return o << "} "; + } + + template <typename stream_type> + static stream_type& print (stream_type& o, const std::vector<half_edge>& hev) + { + o << "half edges: {"; + for(std::size_t i = 0; i < hev.size(); ++i) { + print(o, (hev[i])) << " "; + } + return o << "} "; + } + + template <typename stream_type> + static stream_type& print (stream_type& o, const vertex_data& v) + { + return print(o << "vertex: <" << (v.first) << ", ", (v.second)) << "> "; + } + + template <typename stream_type> + static stream_type& print (stream_type& o, const std::vector<vertex_data>& vv) + { + o << "vertices: {"; + for(std::size_t i = 0; i < vv.size(); ++i) { + print(o, (vv[i])) << " "; + } + return o << "} "; + } + + + + template <typename stream_type> + static inline bool test_insertion(stream_type& stdcout) { + property_merge si; + rectangle_data<Unit> rect; + xl(rect, 0); + yl(rect, 1); + xh(rect, 10); + yh(rect, 11); + + si.insert(rect, 333); + print(stdcout, si.pmd) << std::endl; + + Point pts[4] = {Point(0, 0), Point(10,-3), Point(13, 8), Point(0, 0) }; + polygon_data<Unit> poly; + property_merge si2; + poly.set(pts, pts+3); + si2.insert(poly, 444); + si2.sort_property_merge_data(); + print(stdcout, si2.pmd) << std::endl; + property_merge si3; + poly.set(pts, pts+4); + si3.insert(poly, 444); + si3.sort_property_merge_data(); + stdcout << (si2.pmd == si3.pmd) << std::endl; + std::reverse(pts, pts+4); + property_merge si4; + poly.set(pts, pts+4); + si4.insert(poly, 444); + si4.sort_property_merge_data(); + print(stdcout, si4.pmd) << std::endl; + stdcout << (si2.pmd == si4.pmd) << std::endl; + std::reverse(pts, pts+3); + property_merge si5; + poly.set(pts, pts+4); + si5.insert(poly, 444); + si5.sort_property_merge_data(); + stdcout << (si2.pmd == si5.pmd) << std::endl; + + return true; + } + + template <typename stream_type> + static inline bool test_merge(stream_type& stdcout) { + property_merge si; + rectangle_data<Unit> rect; + xl(rect, 0); + yl(rect, 1); + xh(rect, 10); + yh(rect, 11); + + si.insert(rect, 333); + std::map<std::set<property_type>, polygon_set_data<Unit> > result; + si.merge(result); + print(stdcout, si.pmd) << std::endl; + polygon_set_data<Unit> psd = (*(result.begin())).second; + std::vector<polygon_data<Unit> > polys; + psd.get(polys); + if(polys.size() != 1) { + stdcout << "fail merge 1\n"; + return false; + } + stdcout << (polys[0]) << std::endl; + si.clear(); + std::vector<Point> pts; + pts.push_back(Point(0, 0)); + pts.push_back(Point(10, -10)); + pts.push_back(Point(10, 10)); + polygon_data<Unit> poly; + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(5, 0)); + pts.push_back(Point(-5, -10)); + pts.push_back(Point(-5, 10)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() != 1) { + stdcout << "fail merge 2\n"; + return false; + } + //Polygon { -4 -1, 3 3, -2 3 } + //Polygon { 0 -4, -4 -2, -2 1 } + si.clear(); + pts.clear(); + pts.push_back(Point(-4, -1)); + pts.push_back(Point(3, 3)); + pts.push_back(Point(-2, 3)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(0, -4)); + pts.push_back(Point(-4, -2)); + pts.push_back(Point(-2, 1)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() != 1) { + stdcout << "fail merge 3\n"; + return false; + } + stdcout << "Polygon { -2 2, -2 2, 1 4 } \n"; + stdcout << "Polygon { 2 4, 2 -4, -3 1 } \n"; + si.clear(); + pts.clear(); + pts.push_back(Point(-2, 2)); + pts.push_back(Point(-2, 2)); + pts.push_back(Point(1, 4)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(2, 4)); + pts.push_back(Point(2, -4)); + pts.push_back(Point(-3, 1)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() != 1) { + stdcout << "fail merge 4\n"; + return false; + } + stdcout << (polys[0]) << std::endl; + stdcout << "Polygon { -4 0, -2 -3, 3 -4 } \n"; + stdcout << "Polygon { -1 1, 1 -2, -4 -3 } \n"; + si.clear(); + pts.clear(); + pts.push_back(Point(-4, 0)); + pts.push_back(Point(-2, -3)); + pts.push_back(Point(3, -4)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(-1, 1)); + pts.push_back(Point(1, -2)); + pts.push_back(Point(-4, -3)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() != 1) { + stdcout << "fail merge 5\n"; + return false; + } + stdcout << "Polygon { 2 2, -2 0, 0 1 } \n"; + stdcout << "Polygon { 4 -2, 3 -1, 2 3 } \n"; + si.clear(); + pts.clear(); + pts.push_back(Point(2, 2)); + pts.push_back(Point(-2, 0)); + pts.push_back(Point(0, 1)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(4, -2)); + pts.push_back(Point(3, -1)); + pts.push_back(Point(2, 3)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + if(!result.empty()) { + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() != 1) { + stdcout << "fail merge 6\n"; + return false; + } + stdcout << (polys[0]) << std::endl; + } + stdcout << "Polygon { 0 2, 3 -1, 4 1 } \n"; + stdcout << "Polygon { -4 3, 3 3, 4 2 } \n"; + si.clear(); + pts.clear(); + pts.push_back(Point(0, 2)); + pts.push_back(Point(3, -1)); + pts.push_back(Point(4, 1)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(-4, 3)); + pts.push_back(Point(3, 3)); + pts.push_back(Point(4, 2)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + if(!result.empty()) { + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() == 0) { + stdcout << "fail merge 7\n"; + return false; + } + stdcout << (polys[0]) << std::endl; + } +stdcout << "Polygon { 1 -2, -1 4, 3 -2 } \n"; +stdcout << "Polygon { 0 -3, 3 1, -3 -4 } \n"; + si.clear(); + pts.clear(); + pts.push_back(Point(1, -2)); + pts.push_back(Point(-1, 4)); + pts.push_back(Point(3, -2)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(0, -3)); + pts.push_back(Point(3, 1)); + pts.push_back(Point(-3, -4)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + if(!result.empty()) { + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() == 0) { + stdcout << "fail merge 8\n"; + return false; + } + stdcout << (polys[0]) << std::endl; + } +stdcout << "Polygon { 2 2, 3 0, -3 4 } \n"; +stdcout << "Polygon { -2 -2, 0 0, -1 -1 } \n"; + si.clear(); + pts.clear(); + pts.push_back(Point(2, 2)); + pts.push_back(Point(3, 0)); + pts.push_back(Point(-3, 4)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(-2, -2)); + pts.push_back(Point(0, 0)); + pts.push_back(Point(-1, -1)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + if(!result.empty()) { + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() == 0) { + stdcout << "fail merge 9\n"; + return false; + } + stdcout << (polys[0]) << std::endl; + } + si.clear(); + pts.clear(); + //5624841,17616200,75000,9125000 + //pts.push_back(Point(5624841,75000)); + //pts.push_back(Point(5624841,9125000)); + //pts.push_back(Point(17616200,9125000)); + //pts.push_back(Point(17616200,75000)); +pts.push_back(Point(12262940, 6652520 )); pts.push_back(Point(12125750, 6652520 )); pts.push_back(Point(12121272, 6652961 )); pts.push_back(Point(12112981, 6656396 )); pts.push_back(Point(12106636, 6662741 )); pts.push_back(Point(12103201, 6671032 )); pts.push_back(Point(12103201, 6680007 )); pts.push_back(Point(12106636, 6688298 )); +pts.push_back(Point(12109500, 6691780 )); pts.push_back(Point(12748600, 7330890 )); pts.push_back(Point(15762600, 7330890 )); pts.push_back(Point(15904620, 7472900 )); pts.push_back(Point(15909200, 7473030 )); pts.push_back(Point(15935830, 7476006 )); pts.push_back(Point(15992796, 7499602 )); pts.push_back(Point(16036397, 7543203 )); +pts.push_back(Point(16059993, 7600169 )); pts.push_back(Point(16059993, 7661830 )); pts.push_back(Point(16036397, 7718796 )); pts.push_back(Point(15992796, 7762397 )); pts.push_back(Point(15935830, 7785993 )); pts.push_back(Point(15874169, 7785993 )); pts.push_back(Point(15817203, 7762397 )); pts.push_back(Point(15773602, 7718796 )); +pts.push_back(Point(15750006, 7661830 )); pts.push_back(Point(15747030, 7635200 )); pts.push_back(Point(15746900, 7630620 )); pts.push_back(Point(15670220, 7553930 )); pts.push_back(Point(14872950, 7553930 )); pts.push_back(Point(14872950, 7626170 )); +pts.push_back(Point(14869973, 7661280 )); pts.push_back(Point(14846377, 7718246 )); pts.push_back(Point(14802776, 7761847 )); pts.push_back(Point(14745810, 7785443 )); pts.push_back(Point(14684149, 7785443 )); pts.push_back(Point(14627183, 7761847 )); pts.push_back(Point(14583582, 7718246 )); +pts.push_back(Point(14559986, 7661280 )); pts.push_back(Point(14557070, 7636660 )); pts.push_back(Point(14556670, 7625570 )); pts.push_back(Point(13703330, 7625570 )); pts.push_back(Point(13702930, 7636660 )); pts.push_back(Point(13699993, 7661830 )); pts.push_back(Point(13676397, 7718796 )); +pts.push_back(Point(13632796, 7762397 )); pts.push_back(Point(13575830, 7785993 )); pts.push_back(Point(13514169, 7785993 )); pts.push_back(Point(13457203, 7762397 )); pts.push_back(Point(13436270, 7745670 )); pts.push_back(Point(13432940, 7742520 )); pts.push_back(Point(12963760, 7742520 )); +pts.push_back(Point(12959272, 7742961 )); pts.push_back(Point(12950981, 7746396 )); pts.push_back(Point(12944636, 7752741 )); pts.push_back(Point(12941201, 7761032 )); pts.push_back(Point(12941201, 7770007 )); pts.push_back(Point(12944636, 7778298 )); pts.push_back(Point(12947490, 7781780 )); +pts.push_back(Point(13425330, 8259620 )); pts.push_back(Point(15601330, 8259620 )); pts.push_back(Point(15904620, 8562900 )); pts.push_back(Point(15909200, 8563030 )); pts.push_back(Point(15935830, 8566006 )); pts.push_back(Point(15992796, 8589602 )); pts.push_back(Point(16036397, 8633203 )); +pts.push_back(Point(16059993, 8690169 )); pts.push_back(Point(16059993, 8751830 )); pts.push_back(Point(16036397, 8808796 )); pts.push_back(Point(15992796, 8852397 )); pts.push_back(Point(15935830, 8875993 )); pts.push_back(Point(15874169, 8875993 )); pts.push_back(Point(15817203, 8852397 )); pts.push_back(Point(15773602, 8808796 )); +pts.push_back(Point(15750006, 8751830 )); pts.push_back(Point(15747030, 8725200 )); pts.push_back(Point(15746900, 8720620 )); pts.push_back(Point(15508950, 8482660 )); pts.push_back(Point(14689890, 8482660 )); pts.push_back(Point(14685412, 8483101 )); pts.push_back(Point(14677121, 8486536 )); +pts.push_back(Point(14670776, 8492881 )); pts.push_back(Point(14667341, 8501172 )); pts.push_back(Point(14667341, 8510147 )); pts.push_back(Point(14670776, 8518438 )); pts.push_back(Point(14673630, 8521920 )); pts.push_back(Point(14714620, 8562900 )); pts.push_back(Point(14719200, 8563030 )); pts.push_back(Point(14745830, 8566006 )); +pts.push_back(Point(14802796, 8589602 )); pts.push_back(Point(14846397, 8633203 )); pts.push_back(Point(14869993, 8690169 )); pts.push_back(Point(14869993, 8751830 )); pts.push_back(Point(14846397, 8808796 )); pts.push_back(Point(14802796, 8852397 )); pts.push_back(Point(14745830, 8875993 )); pts.push_back(Point(14684169, 8875993 )); +pts.push_back(Point(14627203, 8852397 )); pts.push_back(Point(14583602, 8808796 )); pts.push_back(Point(14560006, 8751830 )); pts.push_back(Point(14557030, 8725200 )); pts.push_back(Point(14556900, 8720620 )); pts.push_back(Point(14408270, 8571980 )); pts.push_back(Point(13696320, 8571980 )); pts.push_back(Point(13696320, 8675520 )); +pts.push_back(Point(13699963, 8690161 )); pts.push_back(Point(13699963, 8751818 )); pts.push_back(Point(13676368, 8808781 )); pts.push_back(Point(13632771, 8852378 )); pts.push_back(Point(13575808, 8875973 )); pts.push_back(Point(13514151, 8875973 )); pts.push_back(Point(13457188, 8852378 )); pts.push_back(Point(13436270, 8835670 )); pts.push_back(Point(13432940, 8832520 )); +pts.push_back(Point(13281760, 8832520 )); pts.push_back(Point(13277272, 8832961 )); pts.push_back(Point(13268981, 8836396 )); pts.push_back(Point(13262636, 8842741 )); pts.push_back(Point(13259201, 8851032 )); pts.push_back(Point(13259201, 8860007 )); pts.push_back(Point(13262636, 8868298 )); pts.push_back(Point(13265500, 8871780 )); +pts.push_back(Point(13518710, 9125000 )); pts.push_back(Point(16270720, 9125000 )); pts.push_back(Point(16270720, 8939590 )); pts.push_back(Point(17120780, 8939590 )); pts.push_back(Point(17120780, 9125000 )); pts.push_back(Point(17616200, 9125000 )); pts.push_back(Point(17616200, 75000 )); pts.push_back(Point(16024790, 75000 )); +pts.push_back(Point(16021460, 80700 )); pts.push_back(Point(16016397, 88796 )); pts.push_back(Point(15972796, 132397 )); pts.push_back(Point(15915830, 155993 )); pts.push_back(Point(15908730, 157240 )); pts.push_back(Point(15905000, 157800 )); pts.push_back(Point(15516800, 546000 )); pts.push_back(Point(15905000, 934200 )); +pts.push_back(Point(15908730, 934760 )); pts.push_back(Point(15915830, 936006 )); pts.push_back(Point(15972796, 959602 )); pts.push_back(Point(16016397, 1003203 )); pts.push_back(Point(16039993, 1060169 )); pts.push_back(Point(16039993, 1121830 )); pts.push_back(Point(16016397, 1178796 )); pts.push_back(Point(15972796, 1222397 )); +pts.push_back(Point(15915830, 1245993 )); pts.push_back(Point(15854169, 1245993 )); pts.push_back(Point(15797203, 1222397 )); pts.push_back(Point(15753602, 1178796 )); pts.push_back(Point(15730006, 1121830 )); pts.push_back(Point(15728760, 1114730 )); pts.push_back(Point(15728200, 1111000 )); pts.push_back(Point(15363500, 746300 )); +pts.push_back(Point(14602620, 746300 )); pts.push_back(Point(14598142, 746741 )); pts.push_back(Point(14589851, 750176 )); pts.push_back(Point(14583506, 756521 )); pts.push_back(Point(14580071, 764812 )); pts.push_back(Point(14580071, 773787 )); pts.push_back(Point(14583506, 782078 )); pts.push_back(Point(14586360, 785560 )); +pts.push_back(Point(14586370, 785560 )); pts.push_back(Point(14735000, 934200 )); pts.push_back(Point(14738730, 934760 )); pts.push_back(Point(14745830, 936006 )); pts.push_back(Point(14802796, 959602 )); pts.push_back(Point(14846397, 1003203 )); pts.push_back(Point(14869993, 1060169 )); +pts.push_back(Point(14870450, 1062550 )); pts.push_back(Point(14872170, 1071980 )); pts.push_back(Point(14972780, 1071980 )); pts.push_back(Point(15925000, 2024200 )); pts.push_back(Point(15928730, 2024760 )); pts.push_back(Point(15935830, 2026006 )); pts.push_back(Point(15992796, 2049602 )); +pts.push_back(Point(16036397, 2093203 )); pts.push_back(Point(16059993, 2150169 )); pts.push_back(Point(16059993, 2211830 )); pts.push_back(Point(16036397, 2268796 )); pts.push_back(Point(15992796, 2312397 )); pts.push_back(Point(15935830, 2335993 )); pts.push_back(Point(15874169, 2335993 )); +pts.push_back(Point(15817203, 2312397 )); pts.push_back(Point(15773602, 2268796 )); pts.push_back(Point(15750006, 2211830 )); pts.push_back(Point(15748760, 2204730 )); pts.push_back(Point(15748200, 2201000 )); pts.push_back(Point(14869220, 1322020 )); pts.push_back(Point(14088350, 1322020 )); +pts.push_back(Point(14083862, 1322461 )); pts.push_back(Point(14075571, 1325896 )); pts.push_back(Point(14069226, 1332241 )); pts.push_back(Point(14065791, 1340532 )); pts.push_back(Point(14065791, 1349507 )); pts.push_back(Point(14069226, 1357798 )); pts.push_back(Point(14072080, 1361280 )); +pts.push_back(Point(14072090, 1361280 )); pts.push_back(Point(14735000, 2024200 )); pts.push_back(Point(14738730, 2024760 )); pts.push_back(Point(14745830, 2026006 )); pts.push_back(Point(14802796, 2049602 )); pts.push_back(Point(14846397, 2093203 )); pts.push_back(Point(14869993, 2150169 )); +pts.push_back(Point(14869993, 2211830 )); pts.push_back(Point(14846397, 2268796 )); pts.push_back(Point(14802796, 2312397 )); pts.push_back(Point(14745830, 2335993 )); pts.push_back(Point(14684169, 2335993 )); pts.push_back(Point(14627203, 2312397 )); pts.push_back(Point(14583602, 2268796 )); pts.push_back(Point(14560006, 2211830 )); +pts.push_back(Point(14558760, 2204730 )); pts.push_back(Point(14558200, 2201000 )); pts.push_back(Point(13752220, 1395020 )); pts.push_back(Point(12991340, 1395020 )); pts.push_back(Point(12986862, 1395461 )); pts.push_back(Point(12978571, 1398896 )); pts.push_back(Point(12972226, 1405241 )); +pts.push_back(Point(12968791, 1413532 )); pts.push_back(Point(12968791, 1422507 )); pts.push_back(Point(12972226, 1430798 )); pts.push_back(Point(12975080, 1434280 )); pts.push_back(Point(12975090, 1434280 )); pts.push_back(Point(13565000, 2024200 )); pts.push_back(Point(13568730, 2024760 )); pts.push_back(Point(13575830, 2026006 )); +pts.push_back(Point(13632796, 2049602 )); pts.push_back(Point(13676397, 2093203 )); pts.push_back(Point(13699993, 2150169 )); pts.push_back(Point(13699993, 2211830 )); pts.push_back(Point(13676397, 2268796 )); pts.push_back(Point(13632796, 2312397 )); pts.push_back(Point(13575830, 2335993 )); +pts.push_back(Point(13514169, 2335993 )); pts.push_back(Point(13457203, 2312397 )); pts.push_back(Point(13413602, 2268796 )); pts.push_back(Point(13390006, 2211830 )); pts.push_back(Point(13388760, 2204730 )); pts.push_back(Point(13388200, 2201000 )); pts.push_back(Point(12655220, 1468020 )); +pts.push_back(Point(11894340, 1468020 )); pts.push_back(Point(11889862, 1468461 )); pts.push_back(Point(11881571, 1471896 )); pts.push_back(Point(11875226, 1478241 )); pts.push_back(Point(11871791, 1486532 )); pts.push_back(Point(11871791, 1495507 )); +pts.push_back(Point(11875226, 1503798 )); pts.push_back(Point(11878090, 1507280 )); pts.push_back(Point(12395000, 2024200 )); pts.push_back(Point(12398730, 2024760 )); pts.push_back(Point(12405830, 2026006 )); pts.push_back(Point(12462796, 2049602 )); pts.push_back(Point(12506397, 2093203 )); +pts.push_back(Point(12529993, 2150169 )); pts.push_back(Point(12529993, 2211830 )); pts.push_back(Point(12506397, 2268796 )); pts.push_back(Point(12462796, 2312397 )); pts.push_back(Point(12405830, 2335993 )); pts.push_back(Point(12344169, 2335993 )); +pts.push_back(Point(12287203, 2312397 )); pts.push_back(Point(12243602, 2268796 )); pts.push_back(Point(12220006, 2211830 )); pts.push_back(Point(12218760, 2204730 )); pts.push_back(Point(12218200, 2201000 )); pts.push_back(Point(11558220, 1541020 )); +pts.push_back(Point(10797340, 1541020 )); pts.push_back(Point(10792862, 1541461 )); pts.push_back(Point(10784571, 1544896 )); pts.push_back(Point(10778226, 1551241 )); pts.push_back(Point(10774791, 1559532 )); pts.push_back(Point(10774791, 1568507 )); pts.push_back(Point(10778226, 1576798 )); pts.push_back(Point(10781080, 1580280 )); +pts.push_back(Point(10781090, 1580280 )); pts.push_back(Point(11225000, 2024200 )); pts.push_back(Point(11228730, 2024760 )); pts.push_back(Point(11235830, 2026006 )); pts.push_back(Point(11292796, 2049602 )); pts.push_back(Point(11336397, 2093203 )); pts.push_back(Point(11359993, 2150169 )); +pts.push_back(Point(11359993, 2211830 )); pts.push_back(Point(11336397, 2268796 )); pts.push_back(Point(11292796, 2312397 )); pts.push_back(Point(11235830, 2335993 )); pts.push_back(Point(11174169, 2335993 )); pts.push_back(Point(11117203, 2312397 )); pts.push_back(Point(11073602, 2268796 )); pts.push_back(Point(11050006, 2211830 )); +pts.push_back(Point(11048760, 2204730 )); pts.push_back(Point(11048200, 2201000 )); pts.push_back(Point(10461220, 1614020 )); pts.push_back(Point( 5647400, 1614020 )); pts.push_back(Point( 5642912, 1614461 )); +pts.push_back(Point( 5634621, 1617896 )); pts.push_back(Point( 5628276, 1624241 )); pts.push_back(Point( 5624841, 1632532 )); pts.push_back(Point( 5624841, 1641507 )); pts.push_back(Point( 5628276, 1649798 )); pts.push_back(Point( 5631130, 1653280 )); +pts.push_back(Point( 5688490, 1710640 )); pts.push_back(Point( 9722350, 1710640 )); pts.push_back(Point(10034620, 2022900 )); pts.push_back(Point(10039200, 2023030 )); pts.push_back(Point(10065830, 2026006 )); pts.push_back(Point(10122796, 2049602 )); +pts.push_back(Point(10166397, 2093203 )); pts.push_back(Point(10189993, 2150169 )); pts.push_back(Point(10189993, 2211830 )); pts.push_back(Point(10166397, 2268796 )); pts.push_back(Point(10158620, 2279450 )); pts.push_back(Point(10158620, 2404900 )); pts.push_back(Point(10548950, 2795240 )); +pts.push_back(Point(15586950, 2795240 )); pts.push_back(Point(15904620, 3112900 )); pts.push_back(Point(15909200, 3113030 )); pts.push_back(Point(15935830, 3116006 )); pts.push_back(Point(15992796, 3139602 )); pts.push_back(Point(16036397, 3183203 )); pts.push_back(Point(16059993, 3240169 )); pts.push_back(Point(16059993, 3301830 )); +pts.push_back(Point(16036397, 3358796 )); pts.push_back(Point(15992796, 3402397 )); pts.push_back(Point(15935830, 3425993 )); pts.push_back(Point(15874169, 3425993 )); pts.push_back(Point(15817203, 3402397 )); pts.push_back(Point(15773602, 3358796 )); pts.push_back(Point(15750006, 3301830 )); pts.push_back(Point(15747030, 3275200 )); +pts.push_back(Point(15746900, 3270620 )); pts.push_back(Point(15494570, 3018280 )); pts.push_back(Point(14675510, 3018280 )); pts.push_back(Point(14671032, 3018721 )); pts.push_back(Point(14662741, 3022156 )); pts.push_back(Point(14656396, 3028501 )); pts.push_back(Point(14652961, 3036792 )); +pts.push_back(Point(14652961, 3045767 )); pts.push_back(Point(14656396, 3054058 )); pts.push_back(Point(14659260, 3057540 )); pts.push_back(Point(14714620, 3112900 )); pts.push_back(Point(14719200, 3113030 )); pts.push_back(Point(14745830, 3116006 )); pts.push_back(Point(14802796, 3139602 )); +pts.push_back(Point(14846397, 3183203 )); pts.push_back(Point(14869993, 3240169 )); pts.push_back(Point(14869993, 3301830 )); pts.push_back(Point(14846397, 3358796 )); pts.push_back(Point(14802796, 3402397 )); pts.push_back(Point(14745830, 3425993 )); pts.push_back(Point(14684169, 3425993 )); pts.push_back(Point(14627203, 3402397 )); +pts.push_back(Point(14583602, 3358796 )); pts.push_back(Point(14560006, 3301830 )); pts.push_back(Point(14557030, 3275200 )); pts.push_back(Point(14556900, 3270620 )); pts.push_back(Point(14370700, 3084410 )); pts.push_back(Point(13702830, 3084410 )); pts.push_back(Point(13702830, 3263160 )); +pts.push_back(Point(13700003, 3302210 )); pts.push_back(Point(13676407, 3359176 )); pts.push_back(Point(13632806, 3402777 )); pts.push_back(Point(13575840, 3426373 )); pts.push_back(Point(13514179, 3426373 )); pts.push_back(Point(13457213, 3402777 )); pts.push_back(Point(13413612, 3359176 )); +pts.push_back(Point(13390016, 3302210 )); pts.push_back(Point(13387030, 3275200 )); pts.push_back(Point(13386900, 3270620 )); pts.push_back(Point(13266840, 3150550 )); pts.push_back(Point(12532920, 3150550 )); pts.push_back(Point(12532920, 3264990 )); pts.push_back(Point(12529993, 3301820 )); +pts.push_back(Point(12506397, 3358786 )); pts.push_back(Point(12462796, 3402387 )); pts.push_back(Point(12405830, 3425983 )); pts.push_back(Point(12344169, 3425983 )); pts.push_back(Point(12287203, 3402387 )); pts.push_back(Point(12243602, 3358786 )); pts.push_back(Point(12220006, 3301820 )); pts.push_back(Point(12217030, 3275200 )); +pts.push_back(Point(12216900, 3270620 )); pts.push_back(Point(12157460, 3211170 )); pts.push_back(Point(11362030, 3211170 )); pts.push_back(Point(11360250, 3220520 )); pts.push_back(Point(11359993, 3221830 )); pts.push_back(Point(11336397, 3278796 )); +pts.push_back(Point(11292796, 3322397 )); pts.push_back(Point(11235830, 3345993 )); pts.push_back(Point(11174169, 3345993 )); pts.push_back(Point(11117203, 3322397 )); pts.push_back(Point(11096270, 3305670 )); pts.push_back(Point(11092940, 3302520 )); pts.push_back(Point(10680760, 3302520 )); +pts.push_back(Point(10676272, 3302961 )); pts.push_back(Point(10667981, 3306396 )); pts.push_back(Point(10661636, 3312741 )); pts.push_back(Point(10658201, 3321032 )); pts.push_back(Point(10658201, 3330007 )); pts.push_back(Point(10661636, 3338298 )); pts.push_back(Point(10664500, 3341780 )); +pts.push_back(Point(11264260, 3941550 )); pts.push_back(Point(15643260, 3941550 )); pts.push_back(Point(15904620, 4202900 )); pts.push_back(Point(15909200, 4203030 )); pts.push_back(Point(15935830, 4206006 )); pts.push_back(Point(15992796, 4229602 )); +pts.push_back(Point(16036397, 4273203 )); pts.push_back(Point(16059993, 4330169 )); pts.push_back(Point(16059993, 4391830 )); pts.push_back(Point(16036397, 4448796 )); pts.push_back(Point(15992796, 4492397 )); +pts.push_back(Point(15935830, 4515993 )); pts.push_back(Point(15874169, 4515993 )); pts.push_back(Point(15817203, 4492397 )); pts.push_back(Point(15773602, 4448796 )); pts.push_back(Point(15750006, 4391830 )); pts.push_back(Point(15747030, 4365200 )); pts.push_back(Point(15746900, 4360620 )); +pts.push_back(Point(15550880, 4164590 )); pts.push_back(Point(14825070, 4164590 )); pts.push_back(Point(14825070, 4247610 )); pts.push_back(Point(14846397, 4273213 )); pts.push_back(Point(14869993, 4330179 )); pts.push_back(Point(14869993, 4391840 )); pts.push_back(Point(14846397, 4448806 )); +pts.push_back(Point(14802796, 4492407 )); pts.push_back(Point(14745830, 4516003 )); pts.push_back(Point(14684169, 4516003 )); pts.push_back(Point(14627203, 4492407 )); pts.push_back(Point(14583602, 4448806 )); pts.push_back(Point(14560006, 4391840 )); pts.push_back(Point(14557030, 4365200 )); +pts.push_back(Point(14556900, 4360620 )); pts.push_back(Point(14432520, 4236230 )); pts.push_back(Point(13702830, 4236230 )); pts.push_back(Point(13702830, 4352930 )); pts.push_back(Point(13699993, 4391750 )); pts.push_back(Point(13676397, 4448716 )); +pts.push_back(Point(13632796, 4492317 )); pts.push_back(Point(13575830, 4515913 )); pts.push_back(Point(13514169, 4515913 )); pts.push_back(Point(13457203, 4492317 )); pts.push_back(Point(13413602, 4448716 )); pts.push_back(Point(13390006, 4391750 )); pts.push_back(Point(13387030, 4365200 )); +pts.push_back(Point(13386900, 4360620 )); pts.push_back(Point(13334170, 4307880 )); pts.push_back(Point(12532990, 4307880 )); pts.push_back(Point(12532990, 4357550 )); pts.push_back(Point(12529993, 4391760 )); pts.push_back(Point(12506397, 4448726 )); pts.push_back(Point(12462796, 4492327 )); +pts.push_back(Point(12405830, 4515923 )); pts.push_back(Point(12344169, 4515923 )); pts.push_back(Point(12287203, 4492327 )); pts.push_back(Point(12243602, 4448726 )); pts.push_back(Point(12220006, 4391760 )); pts.push_back(Point(12217970, 4378710 )); pts.push_back(Point(12216810, 4368500 )); +pts.push_back(Point(11363190, 4368500 )); pts.push_back(Point(11362030, 4378710 )); pts.push_back(Point(11359983, 4391828 )); pts.push_back(Point(11336388, 4448791 )); pts.push_back(Point(11292791, 4492388 )); pts.push_back(Point(11235828, 4515983 )); pts.push_back(Point(11174171, 4515983 )); pts.push_back(Point(11117208, 4492388 )); +pts.push_back(Point(11096270, 4475670 )); pts.push_back(Point(11092940, 4472520 )); pts.push_back(Point(11057750, 4472520 )); pts.push_back(Point(11053272, 4472961 )); pts.push_back(Point(11044981, 4476396 )); pts.push_back(Point(11038636, 4482741 )); pts.push_back(Point(11035201, 4491032 )); +pts.push_back(Point(11035201, 4500007 )); pts.push_back(Point(11038636, 4508298 )); pts.push_back(Point(11041490, 4511780 )); pts.push_back(Point(11573490, 5043780 )); pts.push_back(Point(15655490, 5043780 )); pts.push_back(Point(15904620, 5292900 )); +pts.push_back(Point(15909200, 5293030 )); pts.push_back(Point(15935830, 5296006 )); pts.push_back(Point(15992796, 5319602 )); pts.push_back(Point(16036397, 5363203 )); pts.push_back(Point(16059993, 5420169 )); pts.push_back(Point(16059993, 5481830 )); pts.push_back(Point(16036397, 5538796 )); +pts.push_back(Point(15992796, 5582397 )); pts.push_back(Point(15935830, 5605993 )); pts.push_back(Point(15874169, 5605993 )); pts.push_back(Point(15817203, 5582397 )); pts.push_back(Point(15773602, 5538796 )); pts.push_back(Point(15750006, 5481830 )); pts.push_back(Point(15747030, 5455200 )); +pts.push_back(Point(15746900, 5450620 )); pts.push_back(Point(15563110, 5266820 )); pts.push_back(Point(14857380, 5266820 )); pts.push_back(Point(14857380, 5382430 )); pts.push_back(Point(14869993, 5420179 )); pts.push_back(Point(14869993, 5481840 )); pts.push_back(Point(14846397, 5538806 )); pts.push_back(Point(14802796, 5582407 )); +pts.push_back(Point(14745830, 5606003 )); pts.push_back(Point(14684169, 5606003 )); pts.push_back(Point(14627203, 5582407 )); pts.push_back(Point(14583602, 5538806 )); pts.push_back(Point(14560006, 5481840 )); pts.push_back(Point(14557030, 5455200 )); pts.push_back(Point(14556900, 5450620 )); pts.push_back(Point(14444750, 5338460 )); +pts.push_back(Point(13702890, 5338460 )); pts.push_back(Point(13702890, 5364400 )); pts.push_back(Point(13699993, 5401800 )); pts.push_back(Point(13676397, 5458766 )); pts.push_back(Point(13632796, 5502367 )); pts.push_back(Point(13575830, 5525963 )); pts.push_back(Point(13514169, 5525963 )); pts.push_back(Point(13457203, 5502367 )); +pts.push_back(Point(13413602, 5458766 )); pts.push_back(Point(13390006, 5401800 )); pts.push_back(Point(13389230, 5397620 )); pts.push_back(Point(13387590, 5388060 )); pts.push_back(Point(12532960, 5388060 )); pts.push_back(Point(12532960, 5446220 )); pts.push_back(Point(12529993, 5481820 )); +pts.push_back(Point(12506397, 5538786 )); pts.push_back(Point(12462796, 5582387 )); pts.push_back(Point(12405830, 5605983 )); pts.push_back(Point(12344169, 5605983 )); pts.push_back(Point(12287203, 5582387 )); pts.push_back(Point(12266270, 5565670 )); pts.push_back(Point(12262940, 5562520 )); pts.push_back(Point(11737750, 5562520 )); +pts.push_back(Point(11733272, 5562961 )); pts.push_back(Point(11724981, 5566396 )); pts.push_back(Point(11718636, 5572741 )); pts.push_back(Point(11715201, 5581032 )); pts.push_back(Point(11715201, 5590007 )); pts.push_back(Point(11718636, 5598298 )); pts.push_back(Point(11721500, 5601780 )); +pts.push_back(Point(12287760, 6168050 )); pts.push_back(Point(15689760, 6168050 )); pts.push_back(Point(15904620, 6382900 )); pts.push_back(Point(15909200, 6383030 )); pts.push_back(Point(15935830, 6386006 )); pts.push_back(Point(15992796, 6409602 )); +pts.push_back(Point(16036397, 6453203 )); pts.push_back(Point(16059993, 6510169 )); pts.push_back(Point(16059993, 6571830 )); pts.push_back(Point(16036397, 6628796 )); pts.push_back(Point(15992796, 6672397 )); pts.push_back(Point(15935830, 6695993 )); pts.push_back(Point(15874169, 6695993 )); +pts.push_back(Point(15817203, 6672397 )); pts.push_back(Point(15773602, 6628796 )); pts.push_back(Point(15750006, 6571830 )); pts.push_back(Point(15747030, 6545200 )); pts.push_back(Point(15746900, 6540620 )); pts.push_back(Point(15597380, 6391090 )); pts.push_back(Point(14858060, 6391090 )); +pts.push_back(Point(14858060, 6473860 )); pts.push_back(Point(14869993, 6510179 )); pts.push_back(Point(14869993, 6571840 )); pts.push_back(Point(14846397, 6628806 )); pts.push_back(Point(14802796, 6672407 )); pts.push_back(Point(14745830, 6696003 )); pts.push_back(Point(14684169, 6696003 )); +pts.push_back(Point(14627203, 6672407 )); pts.push_back(Point(14583602, 6628806 )); pts.push_back(Point(14560006, 6571840 )); pts.push_back(Point(14557030, 6545200 )); pts.push_back(Point(14556900, 6540620 )); pts.push_back(Point(14479020, 6462730 )); +pts.push_back(Point(13702990, 6462730 )); pts.push_back(Point(13702990, 6537170 )); pts.push_back(Point(13700003, 6571840 )); pts.push_back(Point(13676407, 6628806 )); pts.push_back(Point(13632806, 6672407 )); pts.push_back(Point(13575840, 6696003 )); +pts.push_back(Point(13514179, 6696003 )); pts.push_back(Point(13457213, 6672407 )); pts.push_back(Point(13413612, 6628806 )); pts.push_back(Point(13390016, 6571840 )); pts.push_back(Point(13387040, 6545550 )); pts.push_back(Point(13386710, 6534380 )); +pts.push_back(Point(12533290, 6534380 )); pts.push_back(Point(12532960, 6545550 )); pts.push_back(Point(12529983, 6571828 )); pts.push_back(Point(12506388, 6628791 )); pts.push_back(Point(12462791, 6672388 )); pts.push_back(Point(12405828, 6695983 )); +pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 )); pts.push_back(Point(12266270, 6655670 )); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + si.verify1(); + print(stdcout, si.pmd) << std::endl; + if(!result.empty()) { + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + std::vector<Point> outpts; + for(typename polygon_set_data<Unit>::iterator_type itr = psd.begin(); + itr != psd.end(); ++itr) { + outpts.push_back((*itr).first.first); + outpts.push_back((*itr).first.second); + } + gtlsort(outpts.begin(), outpts.end()); + for(std::size_t i = 0; i < outpts.size(); i+=2) { + if(outpts[i] != outpts[i+1]) { + stdcout << "Polygon set not a closed figure\n"; + stdcout << i << std::endl; + stdcout << outpts[i] << " " << outpts[i+1] << std::endl; + return 0; + } + } + polys.clear(); + psd.get(polys); + if(polys.size() == 0) { + stdcout << "fail merge 10\n"; + return false; + } + stdcout << (polys[0]) << std::endl; + } + for(unsigned int i = 0; i < 10; ++i) { + stdcout << "random case # " << i << std::endl; + si.clear(); + pts.clear(); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + polygon_data<Unit> poly1; + poly1.set(pts.begin(), pts.end()); + stdcout << poly1 << std::endl; + si.insert(poly1, 444); + pts.clear(); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + polygon_data<Unit> poly2; + poly2.set(pts.begin(), pts.end()); + stdcout << poly2 << std::endl; + si.insert(poly2, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + if(!result.empty()) { + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() == 0) { + si.clear(); + si.insert(poly1, 333); + result.clear(); + si.merge(result); + psd = (*(result.begin())).second; + std::vector<polygon_data<Unit> > polys1; + psd.get(polys1); + si.clear(); + si.insert(poly2, 333); + result.clear(); + si.merge(result); + psd = (*(result.begin())).second; + std::vector<polygon_data<Unit> > polys2; + psd.get(polys2); + if(!polys1.empty() || !polys2.empty()) { + stdcout << "fail random merge " << i << std::endl; + return false; + } + } + } + if(!polys.empty()) + stdcout << polys.size() << ": " << (polys[0]) << std::endl; + } + return true; + } + + template <typename stream_type> + static inline bool check_rectangle_trio(rectangle_data<Unit> rect1, rectangle_data<Unit> rect2, rectangle_data<Unit> rect3, stream_type& stdcout) { + property_merge si; + std::map<std::set<property_type>, polygon_set_data<Unit> > result; + std::vector<polygon_data<Unit> > polys; + property_merge_90<property_type, Unit> si90; + std::map<std::set<property_type>, polygon_90_set_data<Unit> > result90; + std::vector<polygon_data<Unit> > polys90; + si.insert(rect1, 111); + si90.insert(rect1, 111); + stdcout << rect1 << std::endl; + si.insert(rect2, 222); + si90.insert(rect2, 222); + stdcout << rect2 << std::endl; + si.insert(rect3, 333); + si90.insert(rect3, 333); + stdcout << rect3 << std::endl; + si.merge(result); + si90.merge(result90); + if(result.size() != result90.size()) { + stdcout << "merge failed with size mismatch\n"; + return 0; + } + typename std::map<std::set<property_type>, polygon_90_set_data<Unit> >::iterator itr90 = result90.begin(); + for(typename std::map<std::set<property_type>, polygon_set_data<Unit> >::iterator itr = result.begin(); + itr != result.end(); ++itr) { + for(typename std::set<property_type>::const_iterator set_itr = (*itr).first.begin(); + set_itr != (*itr).first.end(); ++set_itr) { + stdcout << (*set_itr) << " "; + } stdcout << ") \n"; + polygon_set_data<Unit> psd = (*itr).second; + polygon_90_set_data<Unit> psd90 = (*itr90).second; + polys.clear(); + polys90.clear(); + psd.get(polys); + psd90.get(polys90); + if(polys.size() != polys90.size()) { + stdcout << "merge failed with polygon count mismatch\n"; + stdcout << psd << std::endl; + for(std::size_t j = 0; j < polys.size(); ++j) { + stdcout << polys[j] << std::endl; + } + stdcout << "reference\n"; + for(std::size_t j = 0; j < polys90.size(); ++j) { + stdcout << polys90[j] << std::endl; + } + return 0; + } + bool failed = false; + for(std::size_t j = 0; j < polys.size(); ++j) { + stdcout << polys[j] << std::endl; + stdcout << polys90[j] << std::endl; +#ifdef BOOST_POLYGON_ICC +#pragma warning (disable:1572) +#endif + if(area(polys[j]) != area(polys90[j])) { +#ifdef BOOST_POLYGON_ICC +#pragma warning (default:1572) +#endif + stdcout << "merge failed with area mismatch\n"; + failed = true; + } + } + if(failed) return 0; + ++itr90; + } + return true; + } + + template <typename stream_type> + static inline bool test_manhattan_intersection(stream_type& stdcout) { + rectangle_data<Unit> rect1, rect2, rect3; + set_points(rect1, (Point(-1, 2)), (Point(1, 4))); + set_points(rect2, (Point(-1, 2)), (Point(2, 3))); + set_points(rect3, (Point(-3, 0)), (Point(4, 2))); + if(!check_rectangle_trio(rect1, rect2, rect3, stdcout)) { + return false; + } + for(unsigned int i = 0; i < 100; ++i) { + property_merge si; + std::map<std::set<property_type>, polygon_set_data<Unit> > result; + std::vector<polygon_data<Unit> > polys; + property_merge_90<property_type, Unit> si90; + std::map<std::set<property_type>, polygon_90_set_data<Unit> > result90; + std::vector<polygon_data<Unit> > polys90; + stdcout << "random case # " << i << std::endl; + set_points(rect1, (Point(rand()%9-4, rand()%9-4)), (Point(rand()%9-4, rand()%9-4))); + set_points(rect2, (Point(rand()%9-4, rand()%9-4)), (Point(rand()%9-4, rand()%9-4))); + set_points(rect3, (Point(rand()%9-4, rand()%9-4)), (Point(rand()%9-4, rand()%9-4))); + if(!check_rectangle_trio(rect1, rect2, rect3, stdcout)) { + return false; + } + } + return true; + } + + template <typename stream_type> + static inline bool test_intersection(stream_type& stdcout) { + property_merge si; + rectangle_data<Unit> rect; + xl(rect, 0); + yl(rect, 10); + xh(rect, 30); + yh(rect, 20); + si.insert(rect, 333); + xl(rect, 10); + yl(rect, 0); + xh(rect, 20); + yh(rect, 30); + si.insert(rect, 444); + xl(rect, 15); + yl(rect, 0); + xh(rect, 25); + yh(rect, 30); + si.insert(rect, 555); + std::map<std::set<property_type>, polygon_set_data<Unit> > result; + si.merge(result); + print(stdcout, si.pmd) << std::endl; + for(typename std::map<std::set<property_type>, polygon_set_data<Unit> >::iterator itr = result.begin(); + itr != result.end(); ++itr) { + stdcout << "( "; + for(typename std::set<property_type>::const_iterator set_itr = (*itr).first.begin(); + set_itr != (*itr).first.end(); ++set_itr) { + stdcout << (*set_itr) << " "; + } stdcout << ") \n"; + polygon_set_data<Unit> psd = (*itr).second; + stdcout << psd << std::endl; + std::vector<polygon_data<Unit> > polys; + psd.get(polys); + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + } + std::vector<Point> pts; + std::vector<polygon_data<Unit> > polys; + for(unsigned int i = 0; i < 10; ++i) { + property_merge si2; + stdcout << "random case # " << i << std::endl; + si.clear(); + pts.clear(); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + polygon_data<Unit> poly1; + poly1.set(pts.begin(), pts.end()); + stdcout << poly1 << std::endl; + si.insert(poly1, 444); + si2.insert(poly1, 333); + pts.clear(); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + polygon_data<Unit> poly2; + poly2.set(pts.begin(), pts.end()); + stdcout << poly2 << std::endl; + si.insert(poly2, 444); + si2.insert(poly2, 444); + pts.clear(); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + polygon_data<Unit> poly3; + poly3.set(pts.begin(), pts.end()); + stdcout << poly3 << std::endl; + si.insert(poly3, 444); + si2.insert(poly3, 555); + result.clear(); + std::map<std::set<property_type>, polygon_set_data<Unit> > result2; + si.merge(result); + si2.merge(result2); + stdcout << "merged result\n"; + for(typename std::map<std::set<property_type>, polygon_set_data<Unit> >::iterator itr = result.begin(); + itr != result.end(); ++itr) { + stdcout << "( "; + for(typename std::set<property_type>::const_iterator set_itr = (*itr).first.begin(); + set_itr != (*itr).first.end(); ++set_itr) { + stdcout << (*set_itr) << " "; + } stdcout << ") \n"; + polygon_set_data<Unit> psd = (*itr).second; + stdcout << psd << std::endl; + std::vector<polygon_data<Unit> > polys2; + psd.get(polys2); + for(std::size_t ii = 0; ii < polys2.size(); ++ii) { + stdcout << polys2[ii] << std::endl; + } + } + stdcout << "intersected pmd\n"; + print(stdcout, si2.pmd) << std::endl; + stdcout << "intersected result\n"; + for(typename std::map<std::set<property_type>, polygon_set_data<Unit> >::iterator itr = result2.begin(); + itr != result2.end(); ++itr) { + stdcout << "( "; + for(typename std::set<property_type>::const_iterator set_itr = (*itr).first.begin(); + set_itr != (*itr).first.end(); ++set_itr) { + stdcout << (*set_itr) << " "; + } stdcout << ") \n"; + polygon_set_data<Unit> psd = (*itr).second; + stdcout << psd << std::endl; + std::vector<polygon_data<Unit> > polys2; + psd.get(polys2); + for(std::size_t ii = 0; ii < polys2.size(); ++ii) { + stdcout << polys2[ii] << std::endl; + } + } + si.clear(); + for(typename std::map<std::set<property_type>, polygon_set_data<Unit> >::iterator itr = result2.begin(); + itr != result2.end(); ++itr) { + polys.clear(); + (*itr).second.get(polys); + for(std::size_t j = 0; j < polys.size(); ++j) { + si.insert(polys[j], 444); + } + } + result2.clear(); + si.merge(result2); + stdcout << "remerged result\n"; + for(typename std::map<std::set<property_type>, polygon_set_data<Unit> >::iterator itr = result2.begin(); + itr != result2.end(); ++itr) { + stdcout << "( "; + for(typename std::set<property_type>::const_iterator set_itr = (*itr).first.begin(); + set_itr != (*itr).first.end(); ++set_itr) { + stdcout << (*set_itr) << " "; + } stdcout << ") \n"; + polygon_set_data<Unit> psd = (*itr).second; + stdcout << psd << std::endl; + std::vector<polygon_data<Unit> > polys2; + psd.get(polys2); + for(std::size_t ii = 0; ii < polys2.size(); ++ii) { + stdcout << polys2[ii] << std::endl; + } + } + std::vector<polygon_data<Unit> > polys2; + polys.clear(); + (*(result.begin())).second.get(polys); + (*(result2.begin())).second.get(polys2); + if(!(polys == polys2)) { + stdcout << "failed intersection check # " << i << std::endl; + return false; + } + } + return true; + } + }; + + template <typename Unit> + class arbitrary_boolean_op : public scanline_base<Unit> { + private: + + typedef int property_type; + typedef typename scanline_base<Unit>::Point Point; + + //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex + //typedef std::pair<Point, Point> half_edge; + typedef typename scanline_base<Unit>::half_edge half_edge; + + //scanline comparator functor + typedef typename scanline_base<Unit>::less_half_edge less_half_edge; + typedef typename scanline_base<Unit>::less_point less_point; + + //this data structure assocates a property and count to a half edge + typedef std::pair<half_edge, std::pair<property_type, int> > vertex_property; + //this data type stores the combination of many half edges + typedef std::vector<vertex_property> property_merge_data; + + //this is the data type used internally to store the combination of property counts at a given location + typedef std::vector<std::pair<property_type, int> > property_map; + //this data type is used internally to store the combined property data for a given half edge + typedef std::pair<half_edge, property_map> vertex_data; + + property_merge_data pmd; + typename scanline_base<Unit>::evalAtXforYPack evalAtXforYPack_; + + template<typename vertex_data_type> + class less_vertex_data { + typename scanline_base<Unit>::evalAtXforYPack* pack_; + public: + less_vertex_data() : pack_() {} + less_vertex_data(typename scanline_base<Unit>::evalAtXforYPack* pack) : pack_(pack) {} + bool operator()(const vertex_data_type& lvalue, const vertex_data_type& rvalue) const { + less_point lp; + if(lp(lvalue.first.first, rvalue.first.first)) return true; + if(lp(rvalue.first.first, lvalue.first.first)) return false; + Unit x = lvalue.first.first.get(HORIZONTAL); + int just_before_ = 0; + less_half_edge lhe(&x, &just_before_, pack_); + return lhe(lvalue.first, rvalue.first); + } + }; + + template <typename result_type, typename key_type, int op_type> + class boolean_output_functor { + public: + boolean_output_functor() {} + void operator()(result_type& result, const half_edge& edge, const key_type& left, const key_type& right) { + typename std::pair<half_edge, int> elem; + elem.first = edge; + elem.second = 1; + if(edge.second < edge.first) elem.second *= -1; + if(scanline_base<Unit>::is_vertical(edge)) elem.second *= -1; +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op_type == 0) { //OR + if(!left.empty() && right.empty()) { + result.insert_clean(elem); + } else if(!right.empty() && left.empty()) { + elem.second *= -1; + result.insert_clean(elem); + } + } else if(op_type == 1) { //AND + if(left.size() == 2 && right.size() != 2) { + result.insert_clean(elem); + } else if(right.size() == 2 && left.size() != 2) { + elem.second *= -1; + result.insert_clean(elem); + } + } else if(op_type == 2) { //XOR + if(left.size() == 1 && right.size() != 1) { + result.insert_clean(elem); + } else if(right.size() == 1 && left.size() != 1) { + elem.second *= -1; + result.insert_clean(elem); + } + } else { //SUBTRACT + if(left.size() == 1) { + if((*(left.begin())) == 0) { + result.insert_clean(elem); + } + } +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + if(right.size() == 1) { + if((*(right.begin())) == 0) { + elem.second *= -1; + result.insert_clean(elem); + } + } + } + } + }; + + inline void sort_property_merge_data() { + less_vertex_data<vertex_property> lvd(&evalAtXforYPack_); + gtlsort(pmd.begin(), pmd.end(), lvd); + } + public: + inline arbitrary_boolean_op() : pmd(), evalAtXforYPack_() {} + inline arbitrary_boolean_op(const arbitrary_boolean_op& pm) : pmd(pm.pmd), evalAtXforYPack_(pm.evalAtXforYPack_) {} + inline arbitrary_boolean_op& operator=(const arbitrary_boolean_op& pm) { pmd = pm.pmd; return *this; } + + enum BOOLEAN_OP_TYPE { + BOOLEAN_OR = 0, + BOOLEAN_AND = 1, + BOOLEAN_XOR = 2, + BOOLEAN_NOT = 3 + }; + template <typename result_type, typename iT1, typename iT2> + inline void execute(result_type& result, iT1 b1, iT1 e1, iT2 b2, iT2 e2, int op) { + //intersect data + insert(b1, e1, 0); + insert(b2, e2, 1); + property_merge_data tmp_pmd; + //#define BOOST_POLYGON_DEBUG_FILE +#ifdef BOOST_POLYGON_DEBUG_FILE + std::fstream debug_file; + debug_file.open("gtl_debug.txt", std::ios::out); + property_merge<Unit, property_type, std::vector<property_type> >::print(debug_file, pmd); + debug_file.close(); +#endif + if(pmd.empty()) + return; + line_intersection<Unit>::validate_scan(tmp_pmd, pmd.begin(), pmd.end()); + pmd.swap(tmp_pmd); + sort_property_merge_data(); + scanline<Unit, property_type, std::vector<property_type> > sl; + if(op == BOOLEAN_OR) { + boolean_output_functor<result_type, std::vector<property_type>, 0> bof; + sl.scan(result, bof, pmd.begin(), pmd.end()); + } else if(op == BOOLEAN_AND) { + boolean_output_functor<result_type, std::vector<property_type>, 1> bof; + sl.scan(result, bof, pmd.begin(), pmd.end()); + } else if(op == BOOLEAN_XOR) { + boolean_output_functor<result_type, std::vector<property_type>, 2> bof; + sl.scan(result, bof, pmd.begin(), pmd.end()); + } else if(op == BOOLEAN_NOT) { + boolean_output_functor<result_type, std::vector<property_type>, 3> bof; + sl.scan(result, bof, pmd.begin(), pmd.end()); + } + } + + inline void clear() {*this = arbitrary_boolean_op();} + + private: + template <typename iT> + void insert(iT b, iT e, int id) { + for(; + b != e; ++b) { + pmd.push_back(vertex_property(half_edge((*b).first.first, (*b).first.second), + std::pair<property_type, int>(id, (*b).second))); + } + } + + }; + + template <typename Unit, typename stream_type> + bool test_arbitrary_boolean_op(stream_type& stdcout) { + polygon_set_data<Unit> psd; + rectangle_data<Unit> rect; + set_points(rect, point_data<Unit>(0, 0), point_data<Unit>(10, 10)); + psd.insert(rect); + polygon_set_data<Unit> psd2; + set_points(rect, point_data<Unit>(5, 5), point_data<Unit>(15, 15)); + psd2.insert(rect); + std::vector<polygon_data<Unit> > pv; + pv.clear(); + arbitrary_boolean_op<Unit> abo; + polygon_set_data<Unit> psd3; + abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op<Unit>::BOOLEAN_OR); + psd3.get(pv); + for(std::size_t i = 0; i < pv.size(); ++i) { + stdcout << pv[i] << std::endl; + } + pv.clear(); + abo.clear(); + psd3.clear(); + abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op<Unit>::BOOLEAN_AND); + psd3.get(pv); + for(std::size_t i = 0; i < pv.size(); ++i) { + stdcout << pv[i] << std::endl; + } + pv.clear(); + abo.clear(); + psd3.clear(); + abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op<Unit>::BOOLEAN_XOR); + psd3.get(pv); + for(std::size_t i = 0; i < pv.size(); ++i) { + stdcout << pv[i] << std::endl; + } + pv.clear(); + abo.clear(); + psd3.clear(); + abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op<Unit>::BOOLEAN_NOT); + psd3.get(pv); + for(std::size_t i = 0; i < pv.size(); ++i) { + stdcout << pv[i] << std::endl; + } + return true; + } + + + + + + + + + + + + + + + template <typename Unit, typename property_type> + class arbitrary_connectivity_extraction : public scanline_base<Unit> { + private: + + typedef typename scanline_base<Unit>::Point Point; + + //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex + //typedef std::pair<Point, Point> half_edge; + typedef typename scanline_base<Unit>::half_edge half_edge; + + //scanline comparator functor + typedef typename scanline_base<Unit>::less_half_edge less_half_edge; + typedef typename scanline_base<Unit>::less_point less_point; + + //this data structure assocates a property and count to a half edge + typedef std::pair<half_edge, std::pair<property_type, int> > vertex_property; + //this data type stores the combination of many half edges + typedef std::vector<vertex_property> property_merge_data; + + //this is the data type used internally to store the combination of property counts at a given location + typedef std::vector<std::pair<property_type, int> > property_map; + //this data type is used internally to store the combined property data for a given half edge + typedef std::pair<half_edge, property_map> vertex_data; + + property_merge_data pmd; + typename scanline_base<Unit>::evalAtXforYPack evalAtXforYPack_; + + template<typename vertex_data_type> + class less_vertex_data { + typename scanline_base<Unit>::evalAtXforYPack* pack_; + public: + less_vertex_data() : pack_() {} + less_vertex_data(typename scanline_base<Unit>::evalAtXforYPack* pack) : pack_(pack) {} + bool operator()(const vertex_data_type& lvalue, const vertex_data_type& rvalue) const { + less_point lp; + if(lp(lvalue.first.first, rvalue.first.first)) return true; + if(lp(rvalue.first.first, lvalue.first.first)) return false; + Unit x = lvalue.first.first.get(HORIZONTAL); + int just_before_ = 0; + less_half_edge lhe(&x, &just_before_, pack_); + return lhe(lvalue.first, rvalue.first); + } + }; + + + template <typename cT> + static void process_previous_x(cT& output) { + std::map<point_data<Unit>, std::set<property_type> >& y_prop_map = output.first.second; + if(y_prop_map.empty()) return; + Unit x = output.first.first; + for(typename std::map<point_data<Unit>, std::set<property_type> >::iterator itr = + y_prop_map.begin(); itr != y_prop_map.end(); ++itr) { + if((*itr).first.x() < x) { + y_prop_map.erase(y_prop_map.begin(), itr); + continue; + } + for(typename std::set<property_type>::iterator inner_itr = itr->second.begin(); + inner_itr != itr->second.end(); ++inner_itr) { + std::set<property_type>& output_edges = (*(output.second))[*inner_itr]; + typename std::set<property_type>::iterator inner_inner_itr = inner_itr; + ++inner_inner_itr; + for( ; inner_inner_itr != itr->second.end(); ++inner_inner_itr) { + output_edges.insert(output_edges.end(), *inner_inner_itr); + std::set<property_type>& output_edges_2 = (*(output.second))[*inner_inner_itr]; + output_edges_2.insert(output_edges_2.end(), *inner_itr); + } + } + } + } + + template <typename result_type, typename key_type> + class connectivity_extraction_output_functor { + public: + connectivity_extraction_output_functor() {} + void operator()(result_type& result, const half_edge& edge, const key_type& left, const key_type& right) { + Unit& x = result.first.first; + std::map<point_data<Unit>, std::set<property_type> >& y_prop_map = result.first.second; + point_data<Unit> pt = edge.first; + if(pt.x() != x) process_previous_x(result); + x = pt.x(); + std::set<property_type>& output_set = y_prop_map[pt]; + { + for(typename key_type::const_iterator itr1 = + left.begin(); itr1 != left.end(); ++itr1) { + output_set.insert(output_set.end(), *itr1); + } + for(typename key_type::const_iterator itr2 = + right.begin(); itr2 != right.end(); ++itr2) { + output_set.insert(output_set.end(), *itr2); + } + } + std::set<property_type>& output_set2 = y_prop_map[edge.second]; + for(typename key_type::const_iterator itr1 = + left.begin(); itr1 != left.end(); ++itr1) { + output_set2.insert(output_set2.end(), *itr1); + } + for(typename key_type::const_iterator itr2 = + right.begin(); itr2 != right.end(); ++itr2) { + output_set2.insert(output_set2.end(), *itr2); + } + } + }; + + inline void sort_property_merge_data() { + less_vertex_data<vertex_property> lvd(&evalAtXforYPack_); + gtlsort(pmd.begin(), pmd.end(), lvd); + } + public: + inline arbitrary_connectivity_extraction() : pmd(), evalAtXforYPack_() {} + inline arbitrary_connectivity_extraction + (const arbitrary_connectivity_extraction& pm) : pmd(pm.pmd), evalAtXforYPack_(pm.evalAtXforYPack_) {} + inline arbitrary_connectivity_extraction& operator= + (const arbitrary_connectivity_extraction& pm) { pmd = pm.pmd; return *this; } + + template <typename result_type> + inline void execute(result_type& result) { + //intersect data + property_merge_data tmp_pmd; + line_intersection<Unit>::validate_scan(tmp_pmd, pmd.begin(), pmd.end()); + pmd.swap(tmp_pmd); + sort_property_merge_data(); + scanline<Unit, property_type, std::vector<property_type> > sl; + std::pair<std::pair<Unit, std::map<point_data<Unit>, std::set<property_type> > >, + result_type*> output + (std::make_pair(std::make_pair((std::numeric_limits<Unit>::max)(), + std::map<point_data<Unit>, + std::set<property_type> >()), &result)); + connectivity_extraction_output_functor<std::pair<std::pair<Unit, + std::map<point_data<Unit>, std::set<property_type> > >, result_type*>, + std::vector<property_type> > ceof; + sl.scan(output, ceof, pmd.begin(), pmd.end()); + process_previous_x(output); + } + + inline void clear() {*this = arbitrary_connectivity_extraction();} + + template <typename iT> + void populateTouchSetData(iT begin, iT end, + property_type property) { + for( ; begin != end; ++begin) { + pmd.push_back(vertex_property(half_edge((*begin).first.first, (*begin).first.second), + std::pair<property_type, int>(property, (*begin).second))); + } + } + + }; + +} +} +#endif + diff --git a/boost/polygon/detail/transform_detail.hpp b/boost/polygon/detail/transform_detail.hpp new file mode 100644 index 0000000000..2cd3400459 --- /dev/null +++ b/boost/polygon/detail/transform_detail.hpp @@ -0,0 +1,553 @@ +/* + 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_TRANSFORM_DETAIL_HPP +#define BOOST_POLYGON_TRANSFORM_DETAIL_HPP + +namespace boost { namespace polygon{ + // inline std::ostream& operator<< (std::ostream& o, const axis_transformation& r) { + // o << r.atr_; + // return o; + // } + + // inline std::istream& operator>> (std::istream& i, axis_transformation& r) { + // int tmp; + // i >> tmp; + // r = axis_transformation((axis_transformation::ATR)tmp); + // return i; + // } + + // template <typename scale_factor_type> + // inline std::ostream& operator<< (std::ostream& o, const anisotropic_scale_factor<scale_factor_type>& sc) { + // o << sc.scale_[0] << BOOST_POLYGON_SEP << sc.scale_[1] << GTL_SEP << sc.scale_[2]; + // return o; + // } + + // template <typename scale_factor_type> + // inline std::istream& operator>> (std::istream& i, anisotropic_scale_factor<scale_factor_type>& sc) { + // i >> sc.scale_[0] >> sc.scale_[1] >> sc.scale_[2]; + // return i; + // } + + // template <typename coordinate_type> + // inline std::ostream& operator<< (std::ostream& o, const transformation& tr) { + // o << tr.atr_ << BOOST_POLYGON_SEP << tr.p_; + // return o; + // } + + // template <typename coordinate_type> + // inline std::istream& operator>> (std::istream& i, transformation& tr) { + // i >> tr.atr_ >> tr.p_; + // return i; + // } + + + inline axis_transformation::axis_transformation(const orientation_3d& orient) : atr_(NULL_TRANSFORM) { + const ATR tmp[3] = { + UP_EAST_NORTH, //sort by x, then z, then y + EAST_UP_NORTH, //sort by y, then z, then x + EAST_NORTH_UP //sort by z, then y, then x + }; + atr_ = tmp[orient.to_int()]; + } + + inline axis_transformation::axis_transformation(const orientation_2d& orient) : atr_(NULL_TRANSFORM) { + const ATR tmp[3] = { + NORTH_EAST_UP, //sort by z, then x, then y + EAST_NORTH_UP //sort by z, then y, then x + }; + atr_ = tmp[orient.to_int()]; + } + + inline axis_transformation::axis_transformation(const direction_3d& dir) : atr_(NULL_TRANSFORM) { + const ATR tmp[6] = { + DOWN_EAST_NORTH, //sort by -x, then z, then y + UP_EAST_NORTH, //sort by x, then z, then y + EAST_DOWN_NORTH, //sort by -y, then z, then x + EAST_UP_NORTH, //sort by y, then z, then x + EAST_NORTH_DOWN, //sort by -z, then y, then x + EAST_NORTH_UP //sort by z, then y, then x + }; + atr_ = tmp[dir.to_int()]; + } + + inline axis_transformation::axis_transformation(const direction_2d& dir) : atr_(NULL_TRANSFORM) { + const ATR tmp[4] = { + SOUTH_EAST_UP, //sort by z, then x, then y + NORTH_EAST_UP, //sort by z, then x, then y + EAST_SOUTH_UP, //sort by z, then y, then x + EAST_NORTH_UP //sort by z, then y, then x + }; + atr_ = tmp[dir.to_int()]; + } + + inline axis_transformation& axis_transformation::operator=(const axis_transformation& a) { + atr_ = a.atr_; + return *this; + } + + inline axis_transformation& axis_transformation::operator=(const ATR& atr) { + atr_ = atr; + return *this; + } + + inline bool axis_transformation::operator==(const axis_transformation& a) const { + return atr_ == a.atr_; + } + + inline bool axis_transformation::operator!=(const axis_transformation& a) const { + return !(*this == a); + } + + inline bool axis_transformation::operator<(const axis_transformation& a) const { + return atr_ < a.atr_; + } + + inline axis_transformation& axis_transformation::operator+=(const axis_transformation& a){ + bool abit5 = (a.atr_ & 32) != 0; + bool abit4 = (a.atr_ & 16) != 0; + bool abit3 = (a.atr_ & 8) != 0; + bool abit2 = (a.atr_ & 4) != 0; + bool abit1 = (a.atr_ & 2) != 0; + bool abit0 = (a.atr_ & 1) != 0; + bool bit5 = (atr_ & 32) != 0; + bool bit4 = (atr_ & 16) != 0; + bool bit3 = (atr_ & 8) != 0; + bool bit2 = (atr_ & 4) != 0; + bool bit1 = (atr_ & 2) != 0; + bool bit0 = (atr_ & 1) != 0; + int indexes[2][3] = { + { + ((int)((bit5 & bit2) | (bit4 & !bit2)) << 1) + + (int)(bit2 & !bit5), + ((int)((bit4 & bit2) | (bit5 & !bit2)) << 1) + + (int)(!bit5 & !bit2), + ((int)(!bit4 & !bit5) << 1) + + (int)(bit5) + }, + { + ((int)((abit5 & abit2) | (abit4 & !abit2)) << 1) + + (int)(abit2 & !abit5), + ((int)((abit4 & abit2) | (abit5 & !abit2)) << 1) + + (int)(!abit5 & !abit2), + ((int)(!abit4 & !abit5) << 1) + + (int)(abit5) + } + }; + int zero_bits[2][3] = { + {bit0, bit1, bit3}, + {abit0, abit1, abit3} + }; + int nbit3 = zero_bits[0][2] ^ zero_bits[1][indexes[0][2]]; + int nbit1 = zero_bits[0][1] ^ zero_bits[1][indexes[0][1]]; + int nbit0 = zero_bits[0][0] ^ zero_bits[1][indexes[0][0]]; + indexes[0][0] = indexes[1][indexes[0][0]]; + indexes[0][1] = indexes[1][indexes[0][1]]; + indexes[0][2] = indexes[1][indexes[0][2]]; + int nbit5 = (indexes[0][2] == 1); + int nbit4 = (indexes[0][2] == 0); + int nbit2 = (!(nbit5 | nbit4) & (bool)(indexes[0][0] & 1)) | //swap xy + (nbit5 & ((indexes[0][0] & 2) >> 1)) | //z->y x->z + (nbit4 & ((indexes[0][1] & 2) >> 1)); //z->x y->z + atr_ = (ATR)((nbit5 << 5) + + (nbit4 << 4) + + (nbit3 << 3) + + (nbit2 << 2) + + (nbit1 << 1) + nbit0); + return *this; + } + + inline axis_transformation axis_transformation::operator+(const axis_transformation& a) const { + axis_transformation retval(*this); + return retval+=a; + } + + // populate_axis_array writes the three INDIVIDUAL_AXIS values that the + // ATR enum value of 'this' represent into axis_array + inline void axis_transformation::populate_axis_array(INDIVIDUAL_AXIS axis_array[]) const { + bool bit5 = (atr_ & 32) != 0; + bool bit4 = (atr_ & 16) != 0; + bool bit3 = (atr_ & 8) != 0; + bool bit2 = (atr_ & 4) != 0; + bool bit1 = (atr_ & 2) != 0; + bool bit0 = (atr_ & 1) != 0; + axis_array[2] = + (INDIVIDUAL_AXIS)((((int)(!bit4 & !bit5)) << 2) + + ((int)(bit5) << 1) + + bit3); + axis_array[1] = + (INDIVIDUAL_AXIS)((((int)((bit4 & bit2) | (bit5 & !bit2))) << 2)+ + ((int)(!bit5 & !bit2) << 1) + + bit1); + axis_array[0] = + (INDIVIDUAL_AXIS)((((int)((bit5 & bit2) | (bit4 & !bit2))) << 2) + + ((int)(bit2 & !bit5) << 1) + + bit0); + } + + // combine_axis_arrays concatenates this_array and that_array overwriting + // the result into this_array + inline void + axis_transformation::combine_axis_arrays (INDIVIDUAL_AXIS this_array[], + const INDIVIDUAL_AXIS that_array[]){ + int indexes[3] = {this_array[0] >> 1, + this_array[1] >> 1, + this_array[2] >> 1}; + int zero_bits[2][3] = { + {this_array[0] & 1, this_array[1] & 1, this_array[2] & 1}, + {that_array[0] & 1, that_array[1] & 1, that_array[2] & 1} + }; + this_array[0] = that_array[indexes[0]]; + this_array[0] = (INDIVIDUAL_AXIS)((int)this_array[0] & (int)((int)PZ+(int)PY)); + this_array[0] = (INDIVIDUAL_AXIS)((int)this_array[0] | + ((int)zero_bits[0][0] ^ + (int)zero_bits[1][indexes[0]])); + this_array[1] = that_array[indexes[1]]; + this_array[1] = (INDIVIDUAL_AXIS)((int)this_array[1] & (int)((int)PZ+(int)PY)); + this_array[1] = (INDIVIDUAL_AXIS)((int)this_array[1] | + ((int)zero_bits[0][1] ^ + (int)zero_bits[1][indexes[1]])); + this_array[2] = that_array[indexes[2]]; + this_array[2] = (INDIVIDUAL_AXIS)((int)this_array[2] & (int)((int)PZ+(int)PY)); + this_array[2] = (INDIVIDUAL_AXIS)((int)this_array[2] | + ((int)zero_bits[0][2] ^ + (int)zero_bits[1][indexes[2]])); + } + + // write_back_axis_array converts an array of three INDIVIDUAL_AXIS values + // to the ATR enum value and sets 'this' to that value + inline void axis_transformation::write_back_axis_array(const INDIVIDUAL_AXIS this_array[]) { + int bit5 = ((int)this_array[2] & 2) != 0; + int bit4 = !((((int)this_array[2] & 4) != 0) | (((int)this_array[2] & 2) != 0)); + int bit3 = ((int)this_array[2] & 1) != 0; + //bit 2 is the tricky bit + int bit2 = ((!(bit5 | bit4)) & (((int)this_array[0] & 2) != 0)) | //swap xy + (bit5 & (((int)this_array[0] & 4) >> 2)) | //z->y x->z + (bit4 & (((int)this_array[1] & 4) >> 2)); //z->x y->z + int bit1 = ((int)this_array[1] & 1); + int bit0 = ((int)this_array[0] & 1); + atr_ = ATR((bit5 << 5) + + (bit4 << 4) + + (bit3 << 3) + + (bit2 << 2) + + (bit1 << 1) + bit0); + } + + // behavior is deterministic but undefined in the case where illegal + // combinations of directions are passed in. + inline axis_transformation& + axis_transformation::set_directions(const direction_2d& horizontalDir, + const direction_2d& verticalDir){ + int bit2 = (static_cast<orientation_2d>(horizontalDir).to_int()) != 0; + int bit1 = !(verticalDir.to_int() & 1); + int bit0 = !(horizontalDir.to_int() & 1); + atr_ = ATR((bit2 << 2) + (bit1 << 1) + bit0); + return *this; + } + + // behavior is deterministic but undefined in the case where illegal + // combinations of directions are passed in. + inline axis_transformation& axis_transformation::set_directions(const direction_3d& horizontalDir, + const direction_3d& verticalDir, + const direction_3d& proximalDir){ + int this_array[3] = {horizontalDir.to_int(), + verticalDir.to_int(), + proximalDir.to_int()}; + int bit5 = (this_array[2] & 2) != 0; + int bit4 = !(((this_array[2] & 4) != 0) | ((this_array[2] & 2) != 0)); + int bit3 = !((this_array[2] & 1) != 0); + //bit 2 is the tricky bit + int bit2 = (!(bit5 | bit4) & ((this_array[0] & 2) != 0 )) | //swap xy + (bit5 & ((this_array[0] & 4) >> 2)) | //z->y x->z + (bit4 & ((this_array[1] & 4) >> 2)); //z->x y->z + int bit1 = !(this_array[1] & 1); + int bit0 = !(this_array[0] & 1); + atr_ = ATR((bit5 << 5) + + (bit4 << 4) + + (bit3 << 3) + + (bit2 << 2) + + (bit1 << 1) + bit0); + return *this; + } + + template <typename coordinate_type_2> + inline void axis_transformation::transform(coordinate_type_2& x, coordinate_type_2& y) const { + int bit2 = (atr_ & 4) != 0; + int bit1 = (atr_ & 2) != 0; + int bit0 = (atr_ & 1) != 0; + x *= -((bit0 << 1) - 1); + y *= -((bit1 << 1) - 1); + predicated_swap(bit2 != 0,x,y); + } + + template <typename coordinate_type_2> + inline void axis_transformation::transform(coordinate_type_2& x, coordinate_type_2& y, coordinate_type_2& z) const { + int bit5 = (atr_ & 32) != 0; + int bit4 = (atr_ & 16) != 0; + int bit3 = (atr_ & 8) != 0; + int bit2 = (atr_ & 4) != 0; + int bit1 = (atr_ & 2) != 0; + int bit0 = (atr_ & 1) != 0; + x *= -((bit0 << 1) - 1); + y *= -((bit1 << 1) - 1); + z *= -((bit3 << 1) - 1); + predicated_swap(bit2 != 0, x, y); + predicated_swap(bit5 != 0, y, z); + predicated_swap(bit4 != 0, x, z); + } + + inline axis_transformation& axis_transformation::invert_2d() { + int bit2 = ((atr_ & 4) != 0); + int bit1 = ((atr_ & 2) != 0); + int bit0 = ((atr_ & 1) != 0); + //swap bit 0 and bit 1 if bit2 is 1 + predicated_swap(bit2 != 0, bit0, bit1); + bit1 = bit1 << 1; + atr_ = (ATR)(atr_ & (32+16+8+4)); //mask away bit0 and bit1 + atr_ = (ATR)(atr_ | bit0 | bit1); + return *this; + } + + inline axis_transformation axis_transformation::inverse_2d() const { + axis_transformation retval(*this); + return retval.invert_2d(); + } + + inline axis_transformation& axis_transformation::invert() { + int bit5 = ((atr_ & 32) != 0); + int bit4 = ((atr_ & 16) != 0); + int bit3 = ((atr_ & 8) != 0); + int bit2 = ((atr_ & 4) != 0); + int bit1 = ((atr_ & 2) != 0); + int bit0 = ((atr_ & 1) != 0); + predicated_swap(bit2 != 0, bit4, bit5); + predicated_swap(bit4 != 0, bit0, bit3); + predicated_swap(bit5 != 0, bit1, bit3); + predicated_swap(bit2 != 0, bit0, bit1); + atr_ = (ATR)((bit5 << 5) + + (bit4 << 4) + + (bit3 << 3) + + (bit2 << 2) + + (bit1 << 1) + bit0); + return *this; + } + + inline axis_transformation axis_transformation::inverse() const { + axis_transformation retval(*this); + return retval.invert(); + } + + template <typename scale_factor_type> + inline scale_factor_type anisotropic_scale_factor<scale_factor_type>::get(orientation_3d orient) const { + return scale_[orient.to_int()]; + } + + template <typename scale_factor_type> + inline void anisotropic_scale_factor<scale_factor_type>::set(orientation_3d orient, scale_factor_type value) { + scale_[orient.to_int()] = value; + } + + template <typename scale_factor_type> + inline scale_factor_type anisotropic_scale_factor<scale_factor_type>::x() const { return scale_[HORIZONTAL]; } + template <typename scale_factor_type> + inline scale_factor_type anisotropic_scale_factor<scale_factor_type>::y() const { return scale_[VERTICAL]; } + template <typename scale_factor_type> + inline scale_factor_type anisotropic_scale_factor<scale_factor_type>::z() const { return scale_[PROXIMAL]; } + template <typename scale_factor_type> + inline void anisotropic_scale_factor<scale_factor_type>::x(scale_factor_type value) { scale_[HORIZONTAL] = value; } + template <typename scale_factor_type> + inline void anisotropic_scale_factor<scale_factor_type>::y(scale_factor_type value) { scale_[VERTICAL] = value; } + template <typename scale_factor_type> + inline void anisotropic_scale_factor<scale_factor_type>::z(scale_factor_type value) { scale_[PROXIMAL] = value; } + + //concatenation operator (convolve scale factors) + template <typename scale_factor_type> + inline anisotropic_scale_factor<scale_factor_type> anisotropic_scale_factor<scale_factor_type>::operator+(const anisotropic_scale_factor<scale_factor_type>& s) const { + anisotropic_scale_factor<scale_factor_type> retval(*this); + return retval+=s; + } + + //concatenate this with that + template <typename scale_factor_type> + inline const anisotropic_scale_factor<scale_factor_type>& anisotropic_scale_factor<scale_factor_type>::operator+=(const anisotropic_scale_factor<scale_factor_type>& s){ + scale_[0] *= s.scale_[0]; + scale_[1] *= s.scale_[1]; + scale_[2] *= s.scale_[2]; + return *this; + } + + //transform + template <typename scale_factor_type> + inline anisotropic_scale_factor<scale_factor_type>& anisotropic_scale_factor<scale_factor_type>::transform(axis_transformation atr){ + direction_3d dirs[3]; + atr.get_directions(dirs[0],dirs[1],dirs[2]); + scale_factor_type tmp[3] = {scale_[0], scale_[1], scale_[2]}; + for(int i = 0; i < 3; ++i){ + scale_[orientation_3d(dirs[i]).to_int()] = tmp[i]; + } + return *this; + } + + template <typename scale_factor_type> + template <typename coordinate_type_2> + inline void anisotropic_scale_factor<scale_factor_type>::scale(coordinate_type_2& x, coordinate_type_2& y) const { + x = scaling_policy<coordinate_type_2>::round((scale_factor_type)x * get(HORIZONTAL)); + y = scaling_policy<coordinate_type_2>::round((scale_factor_type)y * get(HORIZONTAL)); + } + + template <typename scale_factor_type> + template <typename coordinate_type_2> + inline void anisotropic_scale_factor<scale_factor_type>::scale(coordinate_type_2& x, coordinate_type_2& y, coordinate_type_2& z) const { + scale(x, y); + z = scaling_policy<coordinate_type_2>::round((scale_factor_type)z * get(HORIZONTAL)); + } + + template <typename scale_factor_type> + inline anisotropic_scale_factor<scale_factor_type>& anisotropic_scale_factor<scale_factor_type>::invert() { + x(1/x()); + y(1/y()); + z(1/z()); + return *this; + } + + + template <typename coordinate_type> + inline transformation<coordinate_type>::transformation() : atr_(), p_(0, 0, 0) {;} + + template <typename coordinate_type> + inline transformation<coordinate_type>::transformation(axis_transformation atr) : atr_(atr), p_(0, 0, 0){;} + + template <typename coordinate_type> + inline transformation<coordinate_type>::transformation(axis_transformation::ATR atr) : atr_(atr), p_(0, 0, 0){;} + + template <typename coordinate_type> + template <typename point_type> + inline transformation<coordinate_type>::transformation(const point_type& p) : atr_(), p_(0, 0, 0) { + set_translation(p); + } + + template <typename coordinate_type> + template <typename point_type> + inline transformation<coordinate_type>::transformation(axis_transformation atr, const point_type& p) : + atr_(atr), p_(0, 0, 0) { + set_translation(p); + } + + template <typename coordinate_type> + template <typename point_type> + inline transformation<coordinate_type>::transformation(axis_transformation atr, const point_type& referencePt, const point_type& destinationPt) : atr_(), p_(0, 0, 0) { + transformation<coordinate_type> tmp(referencePt); + transformation<coordinate_type> rotRef(atr); + transformation<coordinate_type> tmpInverse = tmp.inverse(); + point_type decon(referencePt); + deconvolve(decon, destinationPt); + transformation<coordinate_type> displacement(decon); + tmp += rotRef; + tmp += tmpInverse; + tmp += displacement; + (*this) = tmp; + } + + template <typename coordinate_type> + inline transformation<coordinate_type>::transformation(const transformation<coordinate_type>& tr) : + atr_(tr.atr_), p_(tr.p_) {;} + + template <typename coordinate_type> + inline bool transformation<coordinate_type>::operator==(const transformation<coordinate_type>& tr) const { + return atr_ == tr.atr_ && p_ == tr.p_; + } + + template <typename coordinate_type> + inline bool transformation<coordinate_type>::operator!=(const transformation<coordinate_type>& tr) const { + return !(*this == tr); + } + + template <typename coordinate_type> + inline bool transformation<coordinate_type>::operator<(const transformation<coordinate_type>& tr) const { + return atr_ < tr.atr_ || atr_ == tr.atr_ && p_ < tr.p_; + } + + template <typename coordinate_type> + inline transformation<coordinate_type> transformation<coordinate_type>::operator+(const transformation<coordinate_type>& tr) const { + transformation<coordinate_type> retval(*this); + return retval+=tr; + } + + template <typename coordinate_type> + inline const transformation<coordinate_type>& transformation<coordinate_type>::operator+=(const transformation<coordinate_type>& tr){ + //apply the inverse transformation of this to the translation point of that + //and convolve it with this translation point + coordinate_type x, y, z; + transformation<coordinate_type> inv = inverse(); + inv.transform(x, y, z); + p_.set(HORIZONTAL, p_.get(HORIZONTAL) + x); + p_.set(VERTICAL, p_.get(VERTICAL) + y); + p_.set(PROXIMAL, p_.get(PROXIMAL) + z); + //concatenate axis transforms + atr_ += tr.atr_; + return *this; + } + + template <typename coordinate_type> + inline void transformation<coordinate_type>::set_axis_transformation(const axis_transformation& atr) { + atr_ = atr; + } + + template <typename coordinate_type> + template <typename point_type> + inline void transformation<coordinate_type>::get_translation(point_type& p) const { + assign(p, p_); + } + + template <typename coordinate_type> + template <typename point_type> + inline void transformation<coordinate_type>::set_translation(const point_type& p) { + assign(p_, p); + } + + template <typename coordinate_type> + inline void transformation<coordinate_type>::transform(coordinate_type& x, coordinate_type& y) const { + //subtract each component of new origin point + y -= p_.get(VERTICAL); + x -= p_.get(HORIZONTAL); + atr_.transform(x, y); + } + + template <typename coordinate_type> + inline void transformation<coordinate_type>::transform(coordinate_type& x, coordinate_type& y, coordinate_type& z) const { + //subtract each component of new origin point + z -= p_.get(PROXIMAL); + y -= p_.get(VERTICAL); + x -= p_.get(HORIZONTAL); + atr_.transform(x,y,z); + } + + // sets the axis_transform portion to its inverse + // transforms the tranlastion portion by that inverse axis_transform + // multiplies the translation portion by -1 to reverse it + template <typename coordinate_type> + inline transformation<coordinate_type>& transformation<coordinate_type>::invert() { + coordinate_type x = p_.get(HORIZONTAL), y = p_.get(VERTICAL), z = p_.get(PROXIMAL); + atr_.transform(x, y, z); + x *= -1; + y *= -1; + z *= -1; + p_ = point_3d_data<coordinate_type>(x, y, z); + atr_.invert(); + return *this; + } + + template <typename coordinate_type> + inline transformation<coordinate_type> transformation<coordinate_type>::inverse() const { + transformation<coordinate_type> retval(*this); + return retval.invert(); + } +} +} +#endif + + diff --git a/boost/polygon/gmp_override.hpp b/boost/polygon/gmp_override.hpp new file mode 100644 index 0000000000..16cc96fc0a --- /dev/null +++ b/boost/polygon/gmp_override.hpp @@ -0,0 +1,129 @@ +/* + 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_GMP_OVERRIDE_HPP +#define BOOST_POLYGON_GMP_OVERRIDE_HPP +#include <gmpxx.h> +namespace boost { namespace polygon { + + class gmp_int { + private: + inline gmp_int(const mpq_class& input) : v_(input) {} + public: + inline gmp_int() {} + explicit inline gmp_int(long input) : v_(input) {} + inline gmp_int(const gmp_int& input) : v_(input.v_) {} + inline gmp_int& operator=(const gmp_int& that) { + v_ = that.v_; + return (*this); + } + inline gmp_int& operator=(long that) { + v_ = that; + return (*this); + } + inline operator int() const { + std::cout << "cast\n"; + mpz_class num = v_.get_num(); + mpz_class den = v_.get_den(); + num /= den; + return num.get_si(); + } + inline double get_d() const { + return v_.get_d(); + } + inline int get_num() const { + return v_.get_num().get_si(); + } + inline int get_den() const { + return v_.get_den().get_si(); + } + inline bool operator==(const gmp_int& that) const { + return v_ == that.v_; + } + inline bool operator!=(const gmp_int& that) const { + return v_ != that.v_; + } + inline bool operator<(const gmp_int& that) const { + bool retval = v_ < that.v_; + return retval; + } + inline bool operator<=(const gmp_int& that) const { + return v_ <= that.v_; + } + inline bool operator>(const gmp_int& that) const { + return v_ > that.v_; + } + inline bool operator>=(const gmp_int& that) const { + return v_ >= that.v_; + } + inline gmp_int operator+(const gmp_int& b) { + return gmp_int((*this).v_ + b.v_); + } + inline gmp_int operator-(const gmp_int& b) { + return gmp_int((*this).v_ - b.v_); + } + inline gmp_int operator*(const gmp_int& b) { + return gmp_int((*this).v_ * b.v_); + } + inline gmp_int operator/(const gmp_int& b) { + return gmp_int((*this).v_ / b.v_); + } + inline gmp_int& operator+=(const gmp_int& b) { + (*this).v_ += b.v_; + return (*this); + } + inline gmp_int& operator-=(const gmp_int& b) { + (*this).v_ -= b.v_; + return (*this); + } + inline gmp_int& operator*=(const gmp_int& b) { + (*this).v_ *= b.v_; + return (*this); + } + inline gmp_int& operator/=(const gmp_int& b) { + (*this).v_ /= b.v_; + return (*this); + } + inline gmp_int& operator++() { + ++v_; + return (*this); + } + inline gmp_int& operator--() { + --v_; + return (*this); + } + inline gmp_int operator++(int) { + gmp_int retval(*this); + ++(*this); + return retval; + } + inline gmp_int operator--(int) { + gmp_int retval(*this); + --(*this); + return retval; + } + private: + mpq_class v_; + }; + + template <> + struct high_precision_type<int> { + typedef mpq_class type; + }; + + template <> + int convert_high_precision_type<int>(const mpq_class& v) { + mpz_class num = v.get_num(); + mpz_class den = v.get_den(); + num /= den; + return num.get_si(); + }; + +} +} +//== +#endif diff --git a/boost/polygon/gtl.hpp b/boost/polygon/gtl.hpp new file mode 100644 index 0000000000..cabbb63466 --- /dev/null +++ b/boost/polygon/gtl.hpp @@ -0,0 +1,27 @@ +/* + 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 GTL_GTL_HPP +#define GTL_GTL_HPP + +#ifdef __ICC +#pragma warning (disable:1125) +#endif + +#ifdef WIN32 +#pragma warning( disable: 4996 ) +#pragma warning( disable: 4800 ) +#endif + +#define BOOST_POLYGON_NO_DEPS +#include "polygon.hpp" +namespace gtl = boost::polygon; +using namespace boost::polygon::operators; +#if __ICC +#pragma warning (default:1125) +#endif +#endif diff --git a/boost/polygon/interval_concept.hpp b/boost/polygon/interval_concept.hpp new file mode 100644 index 0000000000..9fc5257e7f --- /dev/null +++ b/boost/polygon/interval_concept.hpp @@ -0,0 +1,592 @@ +/* + 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_INTERVAL_CONCEPT_HPP +#define BOOST_POLYGON_INTERVAL_CONCEPT_HPP +#include "isotropy.hpp" +#include "interval_data.hpp" +#include "interval_traits.hpp" + +namespace boost { namespace polygon{ + struct interval_concept {}; + + template <typename T> + struct is_interval_concept { typedef gtl_no type; }; + template <> + struct is_interval_concept<interval_concept> { typedef gtl_yes type; }; + + template <typename T> + struct is_mutable_interval_concept { typedef gtl_no type; }; + template <> + struct is_mutable_interval_concept<interval_concept> { typedef gtl_yes type; }; + + template <typename T, typename CT> + struct interval_coordinate_type_by_concept { typedef void type; }; + template <typename T> + struct interval_coordinate_type_by_concept<T, gtl_yes> { typedef typename interval_traits<T>::coordinate_type type; }; + + template <typename T> + struct interval_coordinate_type { + typedef typename interval_coordinate_type_by_concept< + T, typename is_interval_concept<typename geometry_concept<T>::type>::type>::type type; + }; + + template <typename T, typename CT> + struct interval_difference_type_by_concept { typedef void type; }; + template <typename T> + struct interval_difference_type_by_concept<T, gtl_yes> { + typedef typename coordinate_traits<typename interval_traits<T>::coordinate_type>::coordinate_difference type; }; + + template <typename T> + struct interval_difference_type { + typedef typename interval_difference_type_by_concept< + T, typename is_interval_concept<typename geometry_concept<T>::type>::type>::type type; + }; + + + template <typename T> + typename interval_coordinate_type<T>::type + get(const T& interval, direction_1d dir, + typename enable_if<typename gtl_if<typename is_interval_concept<typename geometry_concept<T>::type>::type>::type>::type * = 0 + ) { + return interval_traits<T>::get(interval, dir); + } + + template <typename T, typename coordinate_type> + void + set(T& interval, direction_1d dir, coordinate_type value, + typename enable_if<typename is_mutable_interval_concept<typename geometry_concept<T>::type>::type>::type * = 0 + ) { + //this may need to be refined + interval_mutable_traits<T>::set(interval, dir, value); + if(high(interval) < low(interval)) + interval_mutable_traits<T>::set(interval, dir.backward(), value); + } + + template <typename T, typename T2, typename T3> + T + construct(T2 low_value, T3 high_value, + typename enable_if<typename is_mutable_interval_concept<typename geometry_concept<T>::type>::type>::type * = 0 + ) { + if(low_value > high_value) std::swap(low_value, high_value); + return interval_mutable_traits<T>::construct(low_value, high_value); + } + + template <typename T, typename T2> + T + copy_construct(const T2& interval, + typename enable_if< typename gtl_and<typename is_mutable_interval_concept<typename geometry_concept<T>::type>::type, + typename is_interval_concept<typename geometry_concept<T2>::type>::type>::type>::type * = 0 + ) { + return construct<T> + (get(interval, LOW ), + get(interval, HIGH)); + } + + template <typename T1, typename T2> + T1 & + assign(T1& lvalue, const T2& rvalue, + typename enable_if< typename gtl_and< typename is_mutable_interval_concept<typename geometry_concept<T1>::type>::type, + typename is_interval_concept<typename geometry_concept<T2>::type>::type>::type>::type * = 0) { + lvalue = copy_construct<T1>(rvalue); + return lvalue; + } + + template <typename T, typename T2> + bool + equivalence(const T& interval1, const T2& interval2, + typename enable_if< typename gtl_and< typename is_interval_concept<typename geometry_concept<T>::type>::type, + typename is_interval_concept<typename geometry_concept<T2>::type>::type>::type>::type * = 0 + ) { + return get(interval1, LOW) == + get(interval2, LOW) && + get(interval1, HIGH) == + get(interval2, HIGH); + } + + struct y_i_contains : gtl_yes {}; + + template <typename interval_type> + typename enable_if< typename gtl_and< y_i_contains, typename is_interval_concept<typename geometry_concept<interval_type>::type>::type >::type, bool>::type + contains(const interval_type& interval, + typename interval_traits<interval_type>::coordinate_type value, + bool consider_touch = true ) { + if(consider_touch) { + return value <= high(interval) && value >= low(interval); + } else { + return value < high(interval) && value > low(interval); + } + } + + template <typename interval_type, typename interval_type_2> + bool + contains(const interval_type& interval, + const interval_type_2& value, bool consider_touch = true, + typename enable_if< typename gtl_and< typename is_interval_concept<typename geometry_concept<interval_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type_2>::type>::type>::type>::type * = 0 + ) { + return contains(interval, get(value, LOW), consider_touch) && + contains(interval, get(value, HIGH), consider_touch); + } + + // get the low coordinate + template <typename interval_type> + typename interval_traits<interval_type>::coordinate_type + low(const interval_type& interval, + typename enable_if< typename is_interval_concept<typename geometry_concept<interval_type>::type>::type>::type * = 0 + ) { return get(interval, LOW); } + + // get the high coordinate + template <typename interval_type> + typename interval_traits<interval_type>::coordinate_type + high(const interval_type& interval, + typename enable_if< typename is_interval_concept<typename geometry_concept<interval_type>::type>::type>::type * = 0 + ) { return get(interval, HIGH); } + + // get the center coordinate + template <typename interval_type> + typename interval_traits<interval_type>::coordinate_type + center(const interval_type& interval, + typename enable_if< typename is_interval_concept<typename geometry_concept<interval_type>::type>::type>::type * = 0 + ) { return (high(interval) + low(interval))/2; } + + + struct y_i_low : gtl_yes {}; + + // set the low coordinate to v + template <typename interval_type> + typename enable_if<typename gtl_and<y_i_low, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, void>::type + low(interval_type& interval, + typename interval_traits<interval_type>::coordinate_type v) { set(interval, LOW, v); } + + struct y_i_high : gtl_yes {}; + + // set the high coordinate to v + template <typename interval_type> + typename enable_if<typename gtl_and<y_i_high, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, void>::type + high(interval_type& interval, + typename interval_traits<interval_type>::coordinate_type v) { set(interval, HIGH, v); } + + // get the magnitude of the interval + template <typename interval_type> + typename interval_difference_type<interval_type>::type + delta(const interval_type& interval, + typename enable_if< typename is_interval_concept<typename geometry_concept<interval_type>::type>::type>::type * = 0 + ) { + typedef typename coordinate_traits<typename interval_traits<interval_type>::coordinate_type>::coordinate_difference diffT; + return (diffT)high(interval) - (diffT)low(interval); } + + struct y_i_flip : gtl_yes {}; + + // flip this about coordinate + template <typename interval_type> + typename enable_if<typename gtl_and<y_i_flip, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, interval_type>::type & + flip(interval_type& interval, + typename interval_traits<interval_type>::coordinate_type axis = 0) { + typename interval_traits<interval_type>::coordinate_type newLow, newHigh; + newLow = 2 * axis - high(interval); + newHigh = 2 * axis - low(interval); + low(interval, newLow); + high(interval, newHigh); + return interval; + } + + struct y_i_scale_up : gtl_yes {}; + + // scale interval by factor + template <typename interval_type> + typename enable_if<typename gtl_and<y_i_scale_up, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, interval_type>::type & + scale_up(interval_type& interval, + typename coordinate_traits<typename interval_traits<interval_type>::coordinate_type>::unsigned_area_type factor) { + typedef typename interval_traits<interval_type>::coordinate_type Unit; + Unit newHigh = high(interval) * (Unit)factor; + low(interval, low(interval) * (Unit)factor); + high(interval, (newHigh)); + return interval; + } + + struct y_i_scale_down : gtl_yes {}; + + template <typename interval_type> + typename enable_if<typename gtl_and<y_i_scale_down, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, interval_type>::type & + scale_down(interval_type& interval, + typename coordinate_traits<typename interval_traits<interval_type>::coordinate_type>::unsigned_area_type factor) { + typedef typename interval_traits<interval_type>::coordinate_type Unit; + typedef typename coordinate_traits<Unit>::coordinate_distance dt; + Unit newHigh = scaling_policy<Unit>::round((dt)(high(interval)) / (dt)factor); + low(interval, scaling_policy<Unit>::round((dt)(low(interval)) / (dt)factor)); + high(interval, (newHigh)); + return interval; + } + + struct y_i_scale : gtl_yes {}; + + template <typename interval_type> + typename enable_if<typename gtl_and<y_i_scale, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, interval_type>::type & + scale(interval_type& interval, double factor) { + typedef typename interval_traits<interval_type>::coordinate_type Unit; + Unit newHigh = scaling_policy<Unit>::round((double)(high(interval)) * factor); + low(interval, scaling_policy<Unit>::round((double)low(interval)* factor)); + high(interval, (newHigh)); + return interval; + } + + // move interval by delta + template <typename interval_type> + interval_type& + move(interval_type& interval, + typename interval_difference_type<interval_type>::type displacement, + typename enable_if<typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type>::type * = 0 + ) { + typedef typename interval_traits<interval_type>::coordinate_type ctype; + typedef typename coordinate_traits<ctype>::coordinate_difference Unit; + Unit len = delta(interval); + low(interval, static_cast<ctype>(static_cast<Unit>(low(interval)) + displacement)); + high(interval, static_cast<ctype>(static_cast<Unit>(low(interval)) + len)); + return interval; + } + + struct y_i_convolve : gtl_yes {}; + + // convolve this with b + template <typename interval_type> + typename enable_if<typename gtl_and<y_i_convolve, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, interval_type>::type & + convolve(interval_type& interval, + typename interval_traits<interval_type>::coordinate_type b) { + typedef typename interval_traits<interval_type>::coordinate_type Unit; + Unit newLow = low(interval) + b; + Unit newHigh = high(interval) + b; + low(interval, newLow); + high(interval, newHigh); + return interval; + } + + struct y_i_deconvolve : gtl_yes {}; + + // deconvolve this with b + template <typename interval_type> + typename enable_if<typename gtl_and<y_i_deconvolve, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, interval_type>::type & + deconvolve(interval_type& interval, + typename interval_traits<interval_type>::coordinate_type b) { + typedef typename interval_traits<interval_type>::coordinate_type Unit; + Unit newLow = low(interval) - b; + Unit newHigh = high(interval) - b; + low(interval, newLow); + high(interval, newHigh); + return interval; + } + + struct y_i_convolve2 : gtl_yes {}; + + // convolve this with b + template <typename interval_type, typename interval_type_2> + typename enable_if< + typename gtl_and_3<y_i_convolve2, + typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type_2>::type>::type>::type, + interval_type>::type & + convolve(interval_type& interval, + const interval_type_2& b) { + typedef typename interval_traits<interval_type>::coordinate_type Unit; + Unit newLow = low(interval) + low(b); + Unit newHigh = high(interval) + high(b); + low(interval, newLow); + high(interval, newHigh); + return interval; + } + + struct y_i_deconvolve2 : gtl_yes {}; + + // deconvolve this with b + template <typename interval_type, typename interval_type_2> + typename enable_if< + typename gtl_and_3< y_i_deconvolve2, + typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type_2>::type>::type>::type, + interval_type>::type & + deconvolve(interval_type& interval, + const interval_type_2& b) { + typedef typename interval_traits<interval_type>::coordinate_type Unit; + Unit newLow = low(interval) - low(b); + Unit newHigh = high(interval) - high(b); + low(interval, newLow); + high(interval, newHigh); + return interval; + } + + struct y_i_reconvolve : gtl_yes {}; + + // reflected convolve this with b + template <typename interval_type, typename interval_type_2> + typename enable_if< + typename gtl_and_3<y_i_reconvolve, + typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type_2>::type>::type>::type, + interval_type>::type & + reflected_convolve(interval_type& interval, + const interval_type_2& b) { + typedef typename interval_traits<interval_type>::coordinate_type Unit; + Unit newLow = low(interval) - high(b); + Unit newHigh = high(interval) - low(b); + low(interval, newLow); + high(interval, newHigh); + return interval; + } + + struct y_i_redeconvolve : gtl_yes {}; + + // reflected deconvolve this with b + template <typename interval_type, typename interval_type_2> + typename enable_if< + typename gtl_and_3< y_i_redeconvolve, + typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type_2>::type>::type>::type, + interval_type>::type & + reflected_deconvolve(interval_type& interval, + const interval_type_2& b) { + typedef typename interval_traits<interval_type>::coordinate_type Unit; + Unit newLow = low(interval) + high(b); + Unit newHigh = high(interval) + low(b); + low(interval, newLow); + high(interval, newHigh); + return interval; + } + + struct y_i_e_dist1 : gtl_yes {}; + + // distance from a coordinate to an interval + template <typename interval_type> + typename enable_if< typename gtl_and<y_i_e_dist1, typename is_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, + typename interval_difference_type<interval_type>::type>::type + euclidean_distance(const interval_type& interval, + typename interval_traits<interval_type>::coordinate_type position) { + typedef typename coordinate_traits<typename interval_traits<interval_type>::coordinate_type>::coordinate_difference Unit; + Unit dist[3] = {0, (Unit)low(interval) - (Unit)position, (Unit)position - (Unit)high(interval)}; + return dist[ (dist[1] > 0) + ((dist[2] > 0) << 1) ]; + } + + struct y_i_e_dist2 : gtl_yes {}; + + // distance between two intervals + template <typename interval_type, typename interval_type_2> + typename enable_if< + typename gtl_and_3<y_i_e_dist2, typename is_interval_concept<typename geometry_concept<interval_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type_2>::type>::type>::type, + typename interval_difference_type<interval_type>::type>::type + euclidean_distance(const interval_type& interval, + const interval_type_2& b) { + typedef typename coordinate_traits<typename interval_traits<interval_type>::coordinate_type>::coordinate_difference Unit; + Unit dist[3] = {0, (Unit)low(interval) - (Unit)high(b), (Unit)low(b) - (Unit)high(interval)}; + return dist[ (dist[1] > 0) + ((dist[2] > 0) << 1) ]; + } + + struct y_i_e_intersects : gtl_yes {}; + + // check if Interval b intersects `this` Interval + template <typename interval_type, typename interval_type_2> + typename enable_if< + typename gtl_and_3<y_i_e_intersects, typename is_interval_concept<typename geometry_concept<interval_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type_2>::type>::type>::type, + bool>::type + intersects(const interval_type& interval, const interval_type_2& b, + bool consider_touch = true) { + return consider_touch ? + (low(interval) <= high(b)) & (high(interval) >= low(b)) : + (low(interval) < high(b)) & (high(interval) > low(b)); + } + + struct y_i_e_bintersect : gtl_yes {}; + + // check if Interval b partially overlaps `this` Interval + template <typename interval_type, typename interval_type_2> + typename enable_if< + typename gtl_and_3<y_i_e_bintersect, typename is_interval_concept<typename geometry_concept<interval_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type_2>::type>::type>::type, + bool>::type + boundaries_intersect(const interval_type& interval, const interval_type_2& b, + bool consider_touch = true) { + return (contains(interval, low(b), consider_touch) || + contains(interval, high(b), consider_touch)) && + (contains(b, low(interval), consider_touch) || + contains(b, high(interval), consider_touch)); + } + + struct y_i_abuts1 : gtl_yes {}; + + // check if they are end to end + template <typename interval_type, typename interval_type_2> + typename enable_if< typename gtl_and_3<y_i_abuts1, typename is_interval_concept<typename geometry_concept<interval_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type_2>::type>::type>::type, + bool>::type + abuts(const interval_type& interval, const interval_type_2& b, direction_1d dir) { + return dir.to_int() ? low(b) == high(interval) : low(interval) == high(b); + } + + struct y_i_abuts2 : gtl_yes {}; + + // check if they are end to end + template <typename interval_type, typename interval_type_2> + typename enable_if< + typename gtl_and_3<y_i_abuts2, typename is_interval_concept<typename geometry_concept<interval_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type_2>::type>::type>::type, + bool>::type + abuts(const interval_type& interval, const interval_type_2& b) { + return abuts(interval, b, HIGH) || abuts(interval, b, LOW); + } + + struct y_i_intersect : gtl_yes {}; + + // set 'this' interval to the intersection of 'this' and b + template <typename interval_type, typename interval_type_2> + typename enable_if< typename gtl_and_3<y_i_intersect, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type_2>::type>::type>::type, + bool>::type + intersect(interval_type& interval, const interval_type_2& b, bool consider_touch = true) { + typedef typename interval_traits<interval_type>::coordinate_type Unit; + Unit lowVal = (std::max)(low(interval), low(b)); + Unit highVal = (std::min)(high(interval), high(b)); + bool valid = consider_touch ? + lowVal <= highVal : + lowVal < highVal; + if(valid) { + low(interval, lowVal); + high(interval, highVal); + } + return valid; + } + + struct y_i_g_intersect : gtl_yes {}; + + // set 'this' interval to the generalized intersection of 'this' and b + template <typename interval_type, typename interval_type_2> + typename enable_if< + typename gtl_and_3<y_i_g_intersect, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type_2>::type>::type>::type, + interval_type>::type & + generalized_intersect(interval_type& interval, const interval_type_2& b) { + typedef typename interval_traits<interval_type>::coordinate_type Unit; + Unit coords[4] = {low(interval), high(interval), low(b), high(b)}; + //consider implementing faster sorting of small fixed length range + gtlsort(coords, coords+4); + low(interval, coords[1]); + high(interval, coords[2]); + return interval; + } + + struct y_i_bloat : gtl_yes {}; + + // bloat the Interval + template <typename interval_type> + typename enable_if< typename gtl_and<y_i_bloat, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, + interval_type>::type & + bloat(interval_type& interval, typename interval_traits<interval_type>::coordinate_type bloating) { + low(interval, low(interval)-bloating); + high(interval, high(interval)+bloating); + return interval; + } + + struct y_i_bloat2 : gtl_yes {}; + + // bloat the specified side of `this` Interval + template <typename interval_type> + typename enable_if< typename gtl_and<y_i_bloat2, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, + interval_type>::type & + bloat(interval_type& interval, direction_1d dir, typename interval_traits<interval_type>::coordinate_type bloating) { + set(interval, dir, get(interval, dir) + dir.get_sign() * bloating); + return interval; + } + + struct y_i_shrink : gtl_yes {}; + + // shrink the Interval + template <typename interval_type> + typename enable_if< typename gtl_and<y_i_shrink, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, + interval_type>::type & + shrink(interval_type& interval, typename interval_traits<interval_type>::coordinate_type shrinking) { + return bloat(interval, -shrinking); + } + + struct y_i_shrink2 : gtl_yes {}; + + // shrink the specified side of `this` Interval + template <typename interval_type> + typename enable_if< typename gtl_and<y_i_shrink2, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, + interval_type>::type & + shrink(interval_type& interval, direction_1d dir, typename interval_traits<interval_type>::coordinate_type shrinking) { + return bloat(interval, dir, -shrinking); + } + + // Enlarge `this` Interval to encompass the specified Interval + template <typename interval_type, typename interval_type_2> + bool + encompass(interval_type& interval, const interval_type_2& b, + typename enable_if< + typename gtl_and< typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type_2>::type>::type>::type>::type * = 0 + ) { + bool retval = !contains(interval, b, true); + low(interval, (std::min)(low(interval), low(b))); + high(interval, (std::max)(high(interval), high(b))); + return retval; + } + + struct y_i_encompass : gtl_yes {}; + + // Enlarge `this` Interval to encompass the specified Interval + template <typename interval_type> + typename enable_if< typename gtl_and<y_i_encompass, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, + bool>::type + encompass(interval_type& interval, typename interval_traits<interval_type>::coordinate_type b) { + bool retval = !contains(interval, b, true); + low(interval, (std::min)(low(interval), b)); + high(interval, (std::max)(high(interval), b)); + return retval; + } + + struct y_i_get_half : gtl_yes {}; + + // gets the half of the interval as an interval + template <typename interval_type> + typename enable_if<typename gtl_and<y_i_get_half, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, interval_type>::type + get_half(const interval_type& interval, direction_1d d1d) { + typedef typename interval_traits<interval_type>::coordinate_type Unit; + Unit c = (get(interval, LOW) + get(interval, HIGH)) / 2; + return construct<interval_type>((d1d == LOW) ? get(interval, LOW) : c, + (d1d == LOW) ? c : get(interval, HIGH)); + } + + struct y_i_join_with : gtl_yes {}; + + // returns true if the 2 intervals exactly touch at one value, like in l1 <= h1 == l2 <= h2 + // sets the argument to the joined interval + template <typename interval_type, typename interval_type_2> + typename enable_if< + typename gtl_and_3<y_i_join_with, typename is_mutable_interval_concept<typename geometry_concept<interval_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type_2>::type>::type>::type, + bool>::type + join_with(interval_type& interval, const interval_type_2& b) { + if(abuts(interval, b)) { + encompass(interval, b); + return true; + } + return false; + } + + template <class T> + template <class T2> + interval_data<T>& interval_data<T>::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template <typename T> + struct geometry_concept<interval_data<T> > { + typedef interval_concept type; + }; +} +} +#endif diff --git a/boost/polygon/interval_data.hpp b/boost/polygon/interval_data.hpp new file mode 100644 index 0000000000..cf2aabf402 --- /dev/null +++ b/boost/polygon/interval_data.hpp @@ -0,0 +1,67 @@ +/* + 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_INTERVAL_DATA_HPP +#define BOOST_POLYGON_INTERVAL_DATA_HPP +#include "isotropy.hpp" +namespace boost { namespace polygon{ + template <typename T> + class interval_data { + public: + typedef T coordinate_type; + inline interval_data() +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + {} + inline interval_data(coordinate_type low, coordinate_type high) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { + coords_[LOW] = low; coords_[HIGH] = high; + } + inline interval_data(const interval_data& that) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { + (*this) = that; + } + inline interval_data& operator=(const interval_data& that) { + coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; return *this; + } + template <typename T2> + inline interval_data& operator=(const T2& rvalue); + inline coordinate_type get(direction_1d dir) const { + return coords_[dir.to_int()]; + } + inline coordinate_type low() const { return coords_[0]; } + inline coordinate_type high() const { return coords_[1]; } + inline bool operator==(const interval_data& that) const { + return low() == that.low() && high() == that.high(); } + inline bool operator!=(const interval_data& that) const { + return low() != that.low() || high() != that.high(); } + inline bool operator<(const interval_data& that) const { + if(coords_[0] < that.coords_[0]) return true; + if(coords_[0] > that.coords_[0]) return false; + if(coords_[1] < that.coords_[1]) return true; + return false; + } + inline bool operator<=(const interval_data& that) const { return !(that < *this); } + inline bool operator>(const interval_data& that) const { return that < *this; } + inline bool operator>=(const interval_data& that) const { return !((*this) < that); } + inline void set(direction_1d dir, coordinate_type value) { + coords_[dir.to_int()] = value; + } +private: + coordinate_type coords_[2]; +}; + +} +} +#endif diff --git a/boost/polygon/interval_traits.hpp b/boost/polygon/interval_traits.hpp new file mode 100644 index 0000000000..a7d74efcda --- /dev/null +++ b/boost/polygon/interval_traits.hpp @@ -0,0 +1,33 @@ +/* + 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_INTERVAL_TRAITS_HPP +#define BOOST_POLYGON_INTERVAL_TRAITS_HPP +namespace boost { namespace polygon{ + template <typename T> + struct interval_traits { + typedef typename T::coordinate_type coordinate_type; + + static inline coordinate_type get(const T& interval, direction_1d dir) { + return interval.get(dir); + } + }; + + template <typename T> + struct interval_mutable_traits { + static inline void set(T& interval, direction_1d dir, typename interval_traits<T>::coordinate_type value) { + interval.set(dir, value); + } + static inline T construct(typename interval_traits<T>::coordinate_type low_value, + typename interval_traits<T>::coordinate_type high_value) { + return T(low_value, high_value); + } + }; +} +} +#endif + diff --git a/boost/polygon/isotropy.hpp b/boost/polygon/isotropy.hpp new file mode 100644 index 0000000000..055707c3e8 --- /dev/null +++ b/boost/polygon/isotropy.hpp @@ -0,0 +1,554 @@ +/* + 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_ISOTROPY_HPP +#define BOOST_POLYGON_ISOTROPY_HPP + +//external +#include <cmath> +#include <cstddef> +#include <cstdlib> +#include <vector> +#include <deque> +#include <map> +#include <set> +#include <list> +//#include <iostream> +#include <algorithm> +#include <limits> +#include <iterator> +#include <string> + +#ifndef BOOST_POLYGON_NO_DEPS + +#include <boost/config.hpp> +#ifdef BOOST_MSVC +#define BOOST_POLYGON_MSVC +#endif +#ifdef BOOST_INTEL +#define BOOST_POLYGON_ICC +#endif +#ifdef BOOST_HAS_LONG_LONG +#define BOOST_POLYGON_USE_LONG_LONG +typedef boost::long_long_type polygon_long_long_type; +typedef boost::ulong_long_type polygon_ulong_long_type; +//typedef long long polygon_long_long_type; +//typedef unsigned long long polygon_ulong_long_type; +#endif +#include <boost/mpl/size_t.hpp> +#include <boost/mpl/protect.hpp> +#include <boost/utility/enable_if.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/mpl/and.hpp> +#include <boost/mpl/or.hpp> +#else + +#ifdef _WIN32 +#define BOOST_POLYGON_MSVC +#endif +#ifdef __ICC +#define BOOST_POLYGON_ICC +#endif +#define BOOST_POLYGON_USE_LONG_LONG +typedef long long polygon_long_long_type; +typedef unsigned long long polygon_ulong_long_type; + + namespace boost { + template <bool B, class T = void> + struct enable_if_c { + typedef T type; + }; + + template <class T> + struct enable_if_c<false, T> {}; + + template <class Cond, class T = void> + struct enable_if : public enable_if_c<Cond::value, T> {}; + + template <bool B, class T> + struct lazy_enable_if_c { + typedef typename T::type type; + }; + + template <class T> + struct lazy_enable_if_c<false, T> {}; + + template <class Cond, class T> + struct lazy_enable_if : public lazy_enable_if_c<Cond::value, T> {}; + + + template <bool B, class T = void> + struct disable_if_c { + typedef T type; + }; + + template <class T> + struct disable_if_c<true, T> {}; + + template <class Cond, class T = void> + struct disable_if : public disable_if_c<Cond::value, T> {}; + + template <bool B, class T> + struct lazy_disable_if_c { + typedef typename T::type type; + }; + + template <class T> + struct lazy_disable_if_c<true, T> {}; + + template <class Cond, class T> + struct lazy_disable_if : public lazy_disable_if_c<Cond::value, T> {}; + } + +#endif + +namespace boost { namespace polygon{ + + enum GEOMETRY_CONCEPT_ID { + COORDINATE_CONCEPT, + INTERVAL_CONCEPT, + POINT_CONCEPT, + POINT_3D_CONCEPT, + RECTANGLE_CONCEPT, + POLYGON_90_CONCEPT, + POLYGON_90_WITH_HOLES_CONCEPT, + POLYGON_45_CONCEPT, + POLYGON_45_WITH_HOLES_CONCEPT, + POLYGON_CONCEPT, + POLYGON_WITH_HOLES_CONCEPT, + POLYGON_90_SET_CONCEPT, + POLYGON_45_SET_CONCEPT, + POLYGON_SET_CONCEPT + }; + + struct undefined_concept {}; + + template <typename T> + struct geometry_concept { typedef undefined_concept type; }; + + template <typename GCT, typename T> + struct view_of {}; + + template <typename T1, typename T2> + view_of<T1, T2> view_as(const T2& obj) { return view_of<T1, T2>(obj); } + + template <typename T> + struct coordinate_traits {}; + + template <typename T> + struct high_precision_type { + typedef long double type; + }; + + template <typename T> + T convert_high_precision_type(const typename high_precision_type<T>::type& v) { + return T(v); + } + + template <> + struct coordinate_traits<int> { + typedef int coordinate_type; + typedef long double area_type; +#ifdef BOOST_POLYGON_USE_LONG_LONG + typedef polygon_long_long_type manhattan_area_type; + typedef polygon_ulong_long_type unsigned_area_type; + typedef polygon_long_long_type coordinate_difference; +#else + typedef long manhattan_area_type; + typedef unsigned long unsigned_area_type; + typedef long coordinate_difference; +#endif + typedef long double coordinate_distance; + }; + +#ifdef BOOST_POLYGON_USE_LONG_LONG + template <> + struct coordinate_traits<polygon_long_long_type> { + typedef polygon_long_long_type coordinate_type; + typedef long double area_type; + typedef polygon_long_long_type manhattan_area_type; + typedef polygon_ulong_long_type unsigned_area_type; + typedef polygon_long_long_type coordinate_difference; + typedef long double coordinate_distance; + }; +#endif + + template <> + struct coordinate_traits<float> { + typedef float coordinate_type; + typedef float area_type; + typedef float manhattan_area_type; + typedef float unsigned_area_type; + typedef float coordinate_difference; + typedef float coordinate_distance; + }; + + template <> + struct coordinate_traits<double> { + typedef double coordinate_type; + typedef double area_type; + typedef double manhattan_area_type; + typedef double unsigned_area_type; + typedef double coordinate_difference; + typedef double coordinate_distance; + }; + + template <> + struct coordinate_traits<long double> { + typedef long double coordinate_type; + typedef long double area_type; + typedef long double manhattan_area_type; + typedef long double unsigned_area_type; + typedef long double coordinate_difference; + typedef long double coordinate_distance; + }; + + template <typename T> + struct scaling_policy { + template <typename T2> + static inline T round(T2 t2) { + return (T)std::floor(t2+0.5); + } + + static inline T round(T t2) { + return t2; + } + }; + + struct coordinate_concept {}; + + template <> + struct geometry_concept<int> { typedef coordinate_concept type; }; +#ifdef BOOST_POLYGON_USE_LONG_LONG + template <> + struct geometry_concept<polygon_long_long_type> { typedef coordinate_concept type; }; +#endif + template <> + struct geometry_concept<float> { typedef coordinate_concept type; }; + template <> + struct geometry_concept<double> { typedef coordinate_concept type; }; + template <> + struct geometry_concept<long double> { typedef coordinate_concept type; }; + +#ifndef BOOST_POLYGON_NO_DEPS + struct gtl_no : mpl::bool_<false> {}; + struct gtl_yes : mpl::bool_<true> {}; + template <typename T, typename T2> + struct gtl_and : mpl::and_<T, T2> {}; + template <typename T, typename T2, typename T3> + struct gtl_and_3 : mpl::and_<T, T2, T3> {}; + template <typename T, typename T2, typename T3, typename T4> + struct gtl_and_4 : mpl::and_<T, T2, T3, T4> {}; +// template <typename T, typename T2> +// struct gtl_or : mpl::or_<T, T2> {}; +// template <typename T, typename T2, typename T3> +// struct gtl_or_3 : mpl::or_<T, T2, T3> {}; +// template <typename T, typename T2, typename T3, typename T4> +// struct gtl_or_4 : mpl::or_<T, T2, T3, T4> {}; +#else + struct gtl_no { static const bool value = false; }; + struct gtl_yes { typedef gtl_yes type; + static const bool value = true; }; + + template <bool T, bool T2> + struct gtl_and_c { typedef gtl_no type; }; + template <> + struct gtl_and_c<true, true> { typedef gtl_yes type; }; + + template <typename T, typename T2> + struct gtl_and : gtl_and_c<T::value, T2::value> {}; + template <typename T, typename T2, typename T3> + struct gtl_and_3 { typedef typename gtl_and< + T, typename gtl_and<T2, T3>::type>::type type; }; + + template <typename T, typename T2, typename T3, typename T4> + struct gtl_and_4 { typedef typename gtl_and_3< + T, T2, typename gtl_and<T3, T4>::type>::type type; }; +#endif + template <typename T, typename T2> + struct gtl_or { typedef gtl_yes type; }; + template <typename T> + struct gtl_or<T, T> { typedef T type; }; + + template <typename T, typename T2, typename T3> + struct gtl_or_3 { typedef typename gtl_or< + T, typename gtl_or<T2, T3>::type>::type type; }; + + template <typename T, typename T2, typename T3, typename T4> + struct gtl_or_4 { typedef typename gtl_or< + T, typename gtl_or_3<T2, T3, T4>::type>::type type; }; + + template <typename T> + struct gtl_not { typedef gtl_no type; }; + template <> + struct gtl_not<gtl_no> { typedef gtl_yes type; }; + + template <typename T> + struct gtl_if { +#ifdef BOOST_POLYGON_MSVC + typedef gtl_no type; +#endif + }; + template <> + struct gtl_if<gtl_yes> { typedef gtl_yes type; }; + + template <typename T, typename T2> + struct gtl_same_type { typedef gtl_no type; }; + template <typename T> + struct gtl_same_type<T, T> { typedef gtl_yes type; }; + template <typename T, typename T2> + struct gtl_different_type { typedef typename gtl_not<typename gtl_same_type<T, T2>::type>::type type; }; + + struct manhattan_domain {}; + struct forty_five_domain {}; + struct general_domain {}; + + template <typename T> + struct geometry_domain { typedef general_domain type; }; + + template <typename domain_type, typename coordinate_type> + struct area_type_by_domain { typedef typename coordinate_traits<coordinate_type>::area_type type; }; + template <typename coordinate_type> + struct area_type_by_domain<manhattan_domain, coordinate_type> { + typedef typename coordinate_traits<coordinate_type>::manhattan_area_type type; }; + + struct y_c_edist : gtl_yes {}; + + template <typename coordinate_type_1, typename coordinate_type_2> + typename enable_if< + typename gtl_and_3<y_c_edist, typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type, + typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, coordinate_concept>::type>::type, + typename coordinate_traits<coordinate_type_1>::coordinate_difference>::type + euclidean_distance(const coordinate_type_1& lvalue, const coordinate_type_2& rvalue) { + typedef typename coordinate_traits<coordinate_type_1>::coordinate_difference Unit; + return (lvalue < rvalue) ? (Unit)rvalue - (Unit)lvalue : (Unit)lvalue - (Unit)rvalue; + } + + + + // predicated_swap swaps a and b if pred is true + + // predicated_swap is guarenteed to behave the same as + // if(pred){ + // T tmp = a; + // a = b; + // b = tmp; + // } + // but will not generate a branch instruction. + // predicated_swap always creates a temp copy of a, but does not + // create more than one temp copy of an input. + // predicated_swap can be used to optimize away branch instructions in C++ + template <class T> + inline bool predicated_swap(const bool& pred, + T& a, + T& b) { + const T tmp = a; + const T* input[2] = {&b, &tmp}; + a = *input[!pred]; + b = *input[pred]; + return pred; + } + + enum direction_1d_enum { LOW = 0, HIGH = 1, + LEFT = 0, RIGHT = 1, + CLOCKWISE = 0, COUNTERCLOCKWISE = 1, + REVERSE = 0, FORWARD = 1, + NEGATIVE = 0, POSITIVE = 1 }; + enum orientation_2d_enum { HORIZONTAL = 0, VERTICAL = 1 }; + enum direction_2d_enum { WEST = 0, EAST = 1, SOUTH = 2, NORTH = 3 }; + enum orientation_3d_enum { PROXIMAL = 2 }; + enum direction_3d_enum { DOWN = 4, UP = 5 }; + enum winding_direction { + clockwise_winding = 0, + counterclockwise_winding = 1, + unknown_winding = 2 + }; + + class direction_2d; + class direction_3d; + class orientation_2d; + + class direction_1d { + private: + unsigned int val_; + explicit direction_1d(int d); + public: + inline direction_1d() : val_(LOW) {} + inline direction_1d(const direction_1d& that) : val_(that.val_) {} + inline direction_1d(const direction_1d_enum val) : val_(val) {} + explicit inline direction_1d(const direction_2d& that); + explicit inline direction_1d(const direction_3d& that); + inline direction_1d& operator = (const direction_1d& d) { + val_ = d.val_; return * this; } + inline bool operator==(direction_1d d) const { return (val_ == d.val_); } + inline bool operator!=(direction_1d d) const { return !((*this) == d); } + inline unsigned int to_int(void) const { return val_; } + inline direction_1d& backward() { val_ ^= 1; return *this; } + inline int get_sign() const { return val_ * 2 - 1; } + }; + + class direction_2d; + + class orientation_2d { + private: + unsigned int val_; + explicit inline orientation_2d(int o); + public: + inline orientation_2d() : val_(HORIZONTAL) {} + inline orientation_2d(const orientation_2d& ori) : val_(ori.val_) {} + inline orientation_2d(const orientation_2d_enum val) : val_(val) {} + explicit inline orientation_2d(const direction_2d& that); + inline orientation_2d& operator=(const orientation_2d& ori) { + val_ = ori.val_; return * this; } + inline bool operator==(orientation_2d that) const { return (val_ == that.val_); } + inline bool operator!=(orientation_2d that) const { return (val_ != that.val_); } + inline unsigned int to_int() const { return (val_); } + inline void turn_90() { val_ = val_^ 1; } + inline orientation_2d get_perpendicular() const { + orientation_2d retval = *this; + retval.turn_90(); + return retval; + } + inline direction_2d get_direction(direction_1d dir) const; + }; + + class direction_2d { + private: + int val_; + + public: + + inline direction_2d() : val_(WEST) {} + + inline direction_2d(const direction_2d& that) : val_(that.val_) {} + + inline direction_2d(const direction_2d_enum val) : val_(val) {} + + inline direction_2d& operator=(const direction_2d& d) { + val_ = d.val_; + return * this; + } + + inline ~direction_2d() { } + + inline bool operator==(direction_2d d) const { return (val_ == d.val_); } + inline bool operator!=(direction_2d d) const { return !((*this) == d); } + inline bool operator< (direction_2d d) const { return (val_ < d.val_); } + inline bool operator<=(direction_2d d) const { return (val_ <= d.val_); } + inline bool operator> (direction_2d d) const { return (val_ > d.val_); } + inline bool operator>=(direction_2d d) const { return (val_ >= d.val_); } + + // Casting to int + inline unsigned int to_int(void) const { return val_; } + + inline direction_2d backward() const { + // flip the LSB, toggles 0 - 1 and 2 - 3 + return direction_2d(direction_2d_enum(val_ ^ 1)); + } + + // Returns a direction 90 degree left (LOW) or right(HIGH) to this one + inline direction_2d turn(direction_1d t) const { + return direction_2d(direction_2d_enum(val_ ^ 3 ^ (val_ >> 1) ^ t.to_int())); + } + + // Returns a direction 90 degree left to this one + inline direction_2d left() const {return turn(HIGH);} + + // Returns a direction 90 degree right to this one + inline direction_2d right() const {return turn(LOW);} + + // N, E are positive, S, W are negative + inline bool is_positive() const {return (val_ & 1);} + inline bool is_negative() const {return !is_positive();} + inline int get_sign() const {return ((is_positive()) << 1) -1;} + + }; + + direction_1d::direction_1d(const direction_2d& that) : val_(that.to_int() & 1) {} + + orientation_2d::orientation_2d(const direction_2d& that) : val_(that.to_int() >> 1) {} + + direction_2d orientation_2d::get_direction(direction_1d dir) const { + return direction_2d(direction_2d_enum((val_ << 1) + dir.to_int())); + } + + class orientation_3d { + private: + unsigned int val_; + explicit inline orientation_3d(int o); + public: + inline orientation_3d() : val_((int)HORIZONTAL) {} + inline orientation_3d(const orientation_3d& ori) : val_(ori.val_) {} + inline orientation_3d(orientation_2d ori) : val_(ori.to_int()) {} + inline orientation_3d(const orientation_3d_enum val) : val_(val) {} + explicit inline orientation_3d(const direction_2d& that); + explicit inline orientation_3d(const direction_3d& that); + inline ~orientation_3d() { } + inline orientation_3d& operator=(const orientation_3d& ori) { + val_ = ori.val_; return * this; } + inline bool operator==(orientation_3d that) const { return (val_ == that.val_); } + inline bool operator!=(orientation_3d that) const { return (val_ != that.val_); } + inline unsigned int to_int() const { return (val_); } + inline direction_3d get_direction(direction_1d dir) const; + }; + + class direction_3d { + private: + int val_; + + public: + + inline direction_3d() : val_(WEST) {} + + inline direction_3d(direction_2d that) : val_(that.to_int()) {} + inline direction_3d(const direction_3d& that) : val_(that.val_) {} + + inline direction_3d(const direction_2d_enum val) : val_(val) {} + inline direction_3d(const direction_3d_enum val) : val_(val) {} + + inline direction_3d& operator=(direction_3d d) { + val_ = d.val_; + return * this; + } + + inline ~direction_3d() { } + + inline bool operator==(direction_3d d) const { return (val_ == d.val_); } + inline bool operator!=(direction_3d d) const { return !((*this) == d); } + inline bool operator< (direction_3d d) const { return (val_ < d.val_); } + inline bool operator<=(direction_3d d) const { return (val_ <= d.val_); } + inline bool operator> (direction_3d d) const { return (val_ > d.val_); } + inline bool operator>=(direction_3d d) const { return (val_ >= d.val_); } + + // Casting to int + inline unsigned int to_int(void) const { return val_; } + + inline direction_3d backward() const { + // flip the LSB, toggles 0 - 1 and 2 - 3 and 4 - 5 + return direction_2d(direction_2d_enum(val_ ^ 1)); + } + + // N, E, U are positive, S, W, D are negative + inline bool is_positive() const {return (val_ & 1);} + inline bool is_negative() const {return !is_positive();} + inline int get_sign() const {return ((is_positive()) << 1) -1;} + + }; + + direction_1d::direction_1d(const direction_3d& that) : val_(that.to_int() & 1) {} + orientation_3d::orientation_3d(const direction_3d& that) : val_(that.to_int() >> 1) {} + orientation_3d::orientation_3d(const direction_2d& that) : val_(that.to_int() >> 1) {} + + direction_3d orientation_3d::get_direction(direction_1d dir) const { + return direction_3d(direction_3d_enum((val_ << 1) + dir.to_int())); + } + +} +} +#endif + diff --git a/boost/polygon/point_3d_concept.hpp b/boost/polygon/point_3d_concept.hpp new file mode 100644 index 0000000000..ab7afeb981 --- /dev/null +++ b/boost/polygon/point_3d_concept.hpp @@ -0,0 +1,270 @@ +/* + 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 GLT_POINT_3D_CONCEPT_HPP +#define GLT_POINT_3D_CONCEPT_HPP +#include "point_concept.hpp" +#include "point_3d_data.hpp" +#include "point_3d_traits.hpp" +namespace boost { namespace polygon{ + struct point_3d_concept {}; + + template <typename T> + struct is_point_3d_concept { typedef gtl_no type; }; + template <> + struct is_point_3d_concept<point_3d_concept> { typedef gtl_yes type; }; + //template <> + //struct is_point_concept<point_3d_concept> { typedef void type; }; + + template <typename T> + struct is_mutable_point_3d_concept { typedef gtl_no type; }; + template <> + struct is_mutable_point_3d_concept<point_3d_concept> { typedef gtl_yes type; }; + + template <typename T, typename CT> + struct point_3d_coordinate_type_by_concept { typedef void type; }; + template <typename T> + struct point_3d_coordinate_type_by_concept<T, gtl_yes> { typedef typename point_3d_traits<T>::coordinate_type type; }; + + template <typename T> + struct point_3d_coordinate_type { + typedef typename point_3d_coordinate_type_by_concept<T, typename is_point_3d_concept<typename geometry_concept<T>::type>::type>::type type; + }; + + template <typename T, typename CT> + struct point_3d_difference_type_by_concept { typedef void type; }; + template <typename T> + struct point_3d_difference_type_by_concept<T, gtl_yes> { + typedef typename coordinate_traits<typename point_3d_traits<T>::coordinate_type>::coordinate_difference type; }; + + template <typename T> + struct point_3d_difference_type { + typedef typename point_3d_difference_type_by_concept< + T, typename is_point_3d_concept<typename geometry_concept<T>::type>::type>::type type; + }; + + template <typename T, typename CT> + struct point_3d_distance_type_by_concept { typedef void type; }; + template <typename T> + struct point_3d_distance_type_by_concept<T, gtl_yes> { + typedef typename coordinate_traits<typename point_3d_traits<T>::coordinate_type>::coordinate_distance type; }; + + template <typename T> + struct point_3d_distance_type { + typedef typename point_3d_distance_type_by_concept< + T, typename is_point_3d_concept<typename geometry_concept<T>::type>::type>::type type; + }; + + struct y_p3d_get : gtl_yes {}; + + template <typename T> + typename enable_if< typename gtl_and<y_p3d_get, typename gtl_if<typename is_point_3d_concept<typename geometry_concept<T>::type>::type>::type>::type, + typename point_3d_coordinate_type<T>::type >::type + get(const T& point, orientation_3d orient) { return point_3d_traits<T>::get(point, orient); } + + struct y_p3d_set : gtl_yes {}; + + template <typename T, typename coordinate_type> + typename enable_if< typename gtl_and<y_p3d_set, typename is_mutable_point_3d_concept<typename geometry_concept<T>::type>::type>::type, void>::type + set(T& point, orientation_3d orient, coordinate_type value) { point_3d_mutable_traits<T>::set(point, orient, value); } + + struct y_p3d_set2 : gtl_yes {}; + + template <typename T, typename coordinate_type> + typename enable_if< typename gtl_and<y_p3d_set2, typename is_mutable_point_3d_concept<typename geometry_concept<T>::type>::type>::type, void>::type + set(T& point, orientation_2d orient, coordinate_type value) { point_3d_mutable_traits<T>::set(point, orient, value); } + + struct y_p3d_construct : gtl_yes {}; + + template <typename T, typename coordinate_type1, typename coordinate_type2, typename coordinate_type3> + typename enable_if< typename gtl_and<y_p3d_construct, typename is_mutable_point_3d_concept<typename geometry_concept<T>::type>::type>::type, T>::type + construct(coordinate_type1 x_value, coordinate_type2 y_value, coordinate_type3 z_value) { + return point_3d_mutable_traits<T>::construct(x_value, y_value, z_value); } + + struct y_p3d_assign : gtl_yes {}; + + template <typename point_3d_type_1, typename point_3d_type_2> + typename enable_if< + typename gtl_and_3<y_p3d_assign, typename is_mutable_point_3d_concept<typename geometry_concept<point_3d_type_1>::type>::type, + typename is_point_3d_concept<typename geometry_concept<point_3d_type_2>::type>::type>::type, + point_3d_type_1>::type & + assign(point_3d_type_1& lvalue, const point_3d_type_2& rvalue) { + set(lvalue, HORIZONTAL, get(rvalue, HORIZONTAL)); + set(lvalue, VERTICAL, get(rvalue, VERTICAL)); + set(lvalue, PROXIMAL, get(rvalue, PROXIMAL)); + return lvalue; + } + + struct y_p3d_z : gtl_yes {}; + + template <typename point_type> + typename enable_if< typename gtl_and<y_p3d_z, typename is_point_3d_concept<typename geometry_concept<point_type>::type>::type>::type, + typename point_3d_traits<point_type>::coordinate_type >::type + z(const point_type& point) { return get(point, PROXIMAL); } + + struct y_p3d_x : gtl_yes {}; + + template <typename point_type, typename coordinate_type> + typename enable_if< typename gtl_and<y_p3d_x, typename is_mutable_point_3d_concept<typename geometry_concept<point_type>::type>::type>::type, void>::type + x(point_type& point, coordinate_type value) { set(point, HORIZONTAL, value); } + + struct y_p3d_y : gtl_yes {}; + + template <typename point_type, typename coordinate_type> + typename enable_if< typename gtl_and<y_p3d_y, typename is_mutable_point_3d_concept<typename geometry_concept<point_type>::type>::type>::type, void>::type + y(point_type& point, coordinate_type value) { set(point, VERTICAL, value); } + + struct y_p3d_z2 : gtl_yes {}; + + template <typename point_type, typename coordinate_type> + typename enable_if< typename gtl_and<y_p3d_z2, typename is_mutable_point_3d_concept<typename geometry_concept<point_type>::type>::type>::type, void>::type + z(point_type& point, coordinate_type value) { set(point, PROXIMAL, value); } + + struct y_p3d_equiv : gtl_yes {}; + + template <typename T, typename T2> + typename enable_if< + typename gtl_and_3<y_p3d_equiv, typename gtl_same_type<point_3d_concept, typename geometry_concept<T>::type>::type, + typename gtl_same_type<point_3d_concept, typename geometry_concept<T2>::type>::type>::type, + bool>::type + equivalence(const T& point1, const T2& point2) { + return x(point1) == x(point2) && y(point1) == y(point2) && z(point1) == z(point2); + } + + struct y_p3d_dist : gtl_yes {}; + + template <typename point_type_1, typename point_type_2> + typename enable_if< typename gtl_and_3<y_p3d_dist, typename is_point_3d_concept<typename geometry_concept<point_type_1>::type>::type, + typename is_point_3d_concept<typename geometry_concept<point_type_2>::type>::type>::type, + typename point_3d_difference_type<point_type_1>::type>::type + euclidean_distance(const point_type_1& point1, const point_type_2& point2, orientation_3d orient) { + typedef typename coordinate_traits<typename point_3d_traits<point_type_1>::coordinate_type>::coordinate_difference return_type; + return_type return_value = + (return_type)get(point1, orient) - (return_type)get(point2, orient); + return return_value < 0 ? -return_value : return_value; + } + + struct y_p3d_man_dist : gtl_yes {}; + + template <typename point_type_1, typename point_type_2> + typename enable_if< typename gtl_and_3<y_p3d_man_dist, typename gtl_same_type<point_3d_concept, typename geometry_concept<point_type_1>::type>::type, + typename gtl_same_type<point_3d_concept, typename geometry_concept<point_type_2>::type>::type>::type, + typename point_3d_difference_type<point_type_1>::type>::type + manhattan_distance(const point_type_1& point1, const point_type_2& point2) { + return euclidean_distance(point1, point2, HORIZONTAL) + euclidean_distance(point1, point2, VERTICAL) + + euclidean_distance(point1, point2, PROXIMAL); + } + + struct y_p3d_dist2 : gtl_yes {}; + + template <typename point_type_1, typename point_type_2> + typename enable_if< typename gtl_and_3< y_p3d_dist2, + typename gtl_same_type<point_3d_concept, typename geometry_concept<point_type_1>::type>::type, + typename gtl_same_type<point_3d_concept, typename geometry_concept<point_type_2>::type>::type>::type, + typename point_3d_distance_type<point_type_1>::type>::type + euclidean_distance(const point_type_1& point1, const point_type_2& point2) { + typedef typename coordinate_traits<typename point_3d_traits<point_type_1>::coordinate_type>::coordinate_distance return_value; + return_value pdist = (return_value)euclidean_distance(point1, point2, PROXIMAL); + pdist *= pdist; + return sqrt((double)(distance_squared(point1, point2) + pdist)); + } + + struct y_p3d_convolve : gtl_yes {}; + + template <typename point_type_1, typename point_type_2> + typename enable_if< typename gtl_and_3< y_p3d_convolve, + typename is_mutable_point_3d_concept<typename geometry_concept<point_type_1>::type>::type, + typename gtl_same_type<point_3d_concept, typename geometry_concept<point_type_2>::type>::type>::type, + point_type_1>::type & + convolve(point_type_1& lvalue, const point_type_2& rvalue) { + x(lvalue, x(lvalue) + x(rvalue)); + y(lvalue, y(lvalue) + y(rvalue)); + z(lvalue, z(lvalue) + z(rvalue)); + return lvalue; + } + + struct y_p3d_deconvolve : gtl_yes {}; + + template <typename point_type_1, typename point_type_2> + typename enable_if< + typename gtl_and_3<y_p3d_deconvolve, typename is_mutable_point_3d_concept<typename geometry_concept<point_type_1>::type>::type, + typename gtl_same_type<point_3d_concept, typename geometry_concept<point_type_2>::type>::type>::type, + point_type_1>::type & + deconvolve(point_type_1& lvalue, const point_type_2& rvalue) { + x(lvalue, x(lvalue) - x(rvalue)); + y(lvalue, y(lvalue) - y(rvalue)); + z(lvalue, z(lvalue) - z(rvalue)); + return lvalue; + } + + struct y_p3d_scale_up : gtl_yes {}; + + template <typename point_type> + typename enable_if< typename gtl_and<y_p3d_scale_up, typename is_mutable_point_3d_concept<typename geometry_concept<point_type>::type>::type>::type, + point_type>::type & + scale_up(point_type& point, + typename coordinate_traits<typename point_3d_traits<point_type>::coordinate_type>::unsigned_area_type factor) { + x(point, x(point) * (typename point_3d_traits<point_type>::coordinate_type)factor); + y(point, y(point) * (typename point_3d_traits<point_type>::coordinate_type)factor); + z(point, z(point) * (typename point_3d_traits<point_type>::coordinate_type)factor); + return point; + } + + struct y_p3d_scale_down : gtl_yes {}; + + template <typename point_type> + typename enable_if< typename gtl_and<y_p3d_scale_down, typename is_mutable_point_3d_concept<typename geometry_concept<point_type>::type>::type>::type, + point_type>::type & + scale_down(point_type& point, + typename coordinate_traits<typename point_3d_traits<point_type>::coordinate_type>::unsigned_area_type factor) { + typedef typename point_3d_traits<point_type>::coordinate_type Unit; + typedef typename coordinate_traits<Unit>::coordinate_distance dt; + x(point, scaling_policy<Unit>::round((dt)(x(point)) / (dt)factor)); + y(point, scaling_policy<Unit>::round((dt)(y(point)) / (dt)factor)); + z(point, scaling_policy<Unit>::round((dt)(z(point)) / (dt)factor)); + return point; + } + + struct y_p3d_scale : gtl_yes {}; + + template <typename point_type, typename scaling_type> + typename enable_if< typename gtl_and<y_p3d_scale, typename is_mutable_point_3d_concept<typename geometry_concept<point_type>::type>::type>::type, + point_type>::type & + scale(point_type& point, + const scaling_type& scaling) { + typedef typename point_3d_traits<point_type>::coordinate_type Unit; + Unit x_(x(point)), y_(y(point)), z_(z(point)); + scaling.scale(x_, y_, z_); + x(point, x_); + y(point, y_); + z(point, z_); + return point; + } + + struct y_p3d_transform : gtl_yes {}; + + template <typename point_type, typename transformation_type> + typename enable_if< typename gtl_and<y_p3d_transform, typename is_mutable_point_3d_concept<typename geometry_concept<point_type>::type>::type>::type, + point_type>::type & + transform(point_type& point, const transformation_type& transformation) { + typedef typename point_3d_traits<point_type>::coordinate_type Unit; + Unit x_(x(point)), y_(y(point)), z_(z(point)); + transformation.transform(x_, y_, z_); + x(point, x_); + y(point, y_); + z(point, z_); + return point; + } + + template <typename T> + struct geometry_concept<point_3d_data<T> > { + typedef point_3d_concept type; + }; +} +} +#endif + diff --git a/boost/polygon/point_3d_data.hpp b/boost/polygon/point_3d_data.hpp new file mode 100644 index 0000000000..c57097cea2 --- /dev/null +++ b/boost/polygon/point_3d_data.hpp @@ -0,0 +1,51 @@ +/* + 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_POINT_3D_DATA_HPP +#define BOOST_POLYGON_POINT_3D_DATA_HPP +namespace boost { namespace polygon{ + template <typename T> + class point_3d_data { + public: + typedef T coordinate_type; + inline point_3d_data():coords_(){} + inline point_3d_data(coordinate_type x, coordinate_type y):coords_() { + coords_[HORIZONTAL] = x; coords_[VERTICAL] = y; coords_[PROXIMAL] = 0; } + inline point_3d_data(coordinate_type x, coordinate_type y, coordinate_type z) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { + coords_[HORIZONTAL] = x; coords_[VERTICAL] = y; coords_[PROXIMAL] = z; } + inline point_3d_data(const point_3d_data& that):coords_() { (*this) = that; } + inline point_3d_data& operator=(const point_3d_data& that) { + coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; + coords_[2] = that.coords_[2]; return *this; } + template <typename T2> + inline point_3d_data& operator=(const T2& rvalue); + inline bool operator==(const point_3d_data& that) const { + return coords_[0] == that.coords_[0] && coords_[1] == that.coords_[1] && coords_[2] == that.coords_[2]; + } + inline bool operator!=(const point_3d_data& that) const { + return !((*this) == that); + } + inline coordinate_type get(orientation_2d orient) const { + return coords_[orient.to_int()]; } + inline coordinate_type get(orientation_3d orient) const { + return coords_[orient.to_int()]; } + inline void set(orientation_2d orient, coordinate_type value) { + coords_[orient.to_int()] = value; } + inline void set(orientation_3d orient, coordinate_type value) { + coords_[orient.to_int()] = value; } + private: + coordinate_type coords_[3]; + }; +} +} +#endif + + diff --git a/boost/polygon/point_3d_traits.hpp b/boost/polygon/point_3d_traits.hpp new file mode 100644 index 0000000000..9f6eb9a3c2 --- /dev/null +++ b/boost/polygon/point_3d_traits.hpp @@ -0,0 +1,35 @@ +/* + 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_POINT_3D_TRAITS_HPP +#define BOOST_POLYGON_POINT_3D_TRAITS_HPP + +#include "isotropy.hpp" + +namespace boost { namespace polygon{ + template <typename T> + struct point_3d_traits { + typedef typename T::coordinate_type coordinate_type; + + static inline coordinate_type get(const T& point, orientation_3d orient) { + return point.get(orient); } + }; + + template <typename T> + struct point_3d_mutable_traits { + static inline void set(T& point, orientation_3d orient, typename point_3d_traits<T>::coordinate_type value) { + point.set(orient, value); } + + static inline T construct(typename point_3d_traits<T>::coordinate_type x_value, + typename point_3d_traits<T>::coordinate_type y_value, + typename point_3d_traits<T>::coordinate_type z_value) { + return T(x_value, y_value, z_value); } + }; +} +} +#endif + diff --git a/boost/polygon/point_concept.hpp b/boost/polygon/point_concept.hpp new file mode 100644 index 0000000000..6e2ce0a520 --- /dev/null +++ b/boost/polygon/point_concept.hpp @@ -0,0 +1,298 @@ +/* + 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_POINT_CONCEPT_HPP +#define BOOST_POLYGON_POINT_CONCEPT_HPP +#include "isotropy.hpp" +#include "point_data.hpp" +#include "point_traits.hpp" + +namespace boost { namespace polygon{ + struct point_concept {}; + + template <typename T> + struct is_point_concept { typedef gtl_no type; }; + template <> + struct is_point_concept<point_concept> { typedef gtl_yes type; }; + + struct point_3d_concept; + template <> + struct is_point_concept<point_3d_concept> { typedef gtl_yes type; }; + + template <typename T> + struct is_mutable_point_concept { typedef gtl_no type; }; + template <> + struct is_mutable_point_concept<point_concept> { typedef gtl_yes type; }; + + template <typename T, typename CT> + struct point_coordinate_type_by_concept { typedef void type; }; + template <typename T> + struct point_coordinate_type_by_concept<T, gtl_yes> { typedef typename point_traits<T>::coordinate_type type; }; + + template <typename T> + struct point_coordinate_type { + typedef typename point_coordinate_type_by_concept<T, typename is_point_concept<typename geometry_concept<T>::type>::type>::type type; + }; + + template <typename T, typename CT> + struct point_difference_type_by_concept { typedef void type; }; + template <typename T> + struct point_difference_type_by_concept<T, gtl_yes> { + typedef typename coordinate_traits<typename point_traits<T>::coordinate_type>::coordinate_difference type; }; + + template <typename T> + struct point_difference_type { + typedef typename point_difference_type_by_concept< + T, typename is_point_concept<typename geometry_concept<T>::type>::type>::type type; + }; + + template <typename T, typename CT> + struct point_distance_type_by_concept { typedef void type; }; + template <typename T> + struct point_distance_type_by_concept<T, gtl_yes> { + typedef typename coordinate_traits<typename point_traits<T>::coordinate_type>::coordinate_distance type; }; + + template <typename T> + struct point_distance_type { + typedef typename point_distance_type_by_concept< + T, typename is_point_concept<typename geometry_concept<T>::type>::type>::type type; + }; + + template <typename T> + typename point_coordinate_type<T>::type + get(const T& point, orientation_2d orient, + typename enable_if< typename gtl_if<typename is_point_concept<typename geometry_concept<T>::type>::type>::type>::type * = 0 + ) { + return point_traits<T>::get(point, orient); + } + + template <typename T, typename coordinate_type> + void + set(T& point, orientation_2d orient, coordinate_type value, + typename enable_if<typename is_mutable_point_concept<typename geometry_concept<T>::type>::type>::type * = 0 + ) { + point_mutable_traits<T>::set(point, orient, value); + } + + template <typename T, typename coordinate_type1, typename coordinate_type2> + T + construct(coordinate_type1 x_value, coordinate_type2 y_value, + typename enable_if<typename is_mutable_point_concept<typename geometry_concept<T>::type>::type>::type * = 0 + ) { + return point_mutable_traits<T>::construct(x_value, y_value); + } + + template <typename T1, typename T2> + T1& + assign(T1& lvalue, const T2& rvalue, + typename enable_if< typename gtl_and< typename is_mutable_point_concept<typename geometry_concept<T1>::type>::type, + typename is_point_concept<typename geometry_concept<T2>::type>::type>::type>::type * = 0 + ) { + set(lvalue, HORIZONTAL, get(rvalue, HORIZONTAL)); + set(lvalue, VERTICAL, get(rvalue, VERTICAL)); + return lvalue; + } + + struct y_p_x : gtl_yes {}; + + template <typename point_type> + typename enable_if< typename gtl_and<y_p_x, typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, + typename point_traits<point_type>::coordinate_type >::type + x(const point_type& point) { + return get(point, HORIZONTAL); + } + + struct y_p_y : gtl_yes {}; + + template <typename point_type> + typename enable_if< typename gtl_and<y_p_y, typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, + typename point_traits<point_type>::coordinate_type >::type + y(const point_type& point) { + return get(point, VERTICAL); + } + + struct y_p_sx : gtl_yes {}; + + template <typename point_type, typename coordinate_type> + typename enable_if<typename gtl_and<y_p_sx, typename is_mutable_point_concept<typename geometry_concept<point_type>::type>::type>::type, + void>::type + x(point_type& point, coordinate_type value) { + set(point, HORIZONTAL, value); + } + + struct y_p_sy : gtl_yes {}; + + template <typename point_type, typename coordinate_type> + typename enable_if<typename gtl_and<y_p_sy, typename is_mutable_point_concept<typename geometry_concept<point_type>::type>::type>::type, + void>::type + y(point_type& point, coordinate_type value) { + set(point, VERTICAL, value); + } + + template <typename T, typename T2> + bool + equivalence(const T& point1, const T2& point2, + typename enable_if< typename gtl_and<typename gtl_same_type<point_concept, typename geometry_concept<T>::type>::type, + typename is_point_concept<typename geometry_concept<T2>::type>::type>::type>::type * = 0 + ) { + typename point_traits<T>::coordinate_type x1 = x(point1); + typename point_traits<T2>::coordinate_type x2 = get(point2, HORIZONTAL); + typename point_traits<T>::coordinate_type y1 = get(point1, VERTICAL); + typename point_traits<T2>::coordinate_type y2 = y(point2); + return x1 == x2 && y1 == y2; + } + + template <typename point_type_1, typename point_type_2> + typename point_difference_type<point_type_1>::type + manhattan_distance(const point_type_1& point1, const point_type_2& point2, + typename enable_if< typename gtl_and<typename gtl_same_type<point_concept, typename geometry_concept<point_type_1>::type>::type, + typename is_point_concept<typename geometry_concept<point_type_2>::type>::type>::type>::type * = 0) { + return euclidean_distance(point1, point2, HORIZONTAL) + euclidean_distance(point1, point2, VERTICAL); + } + + struct y_i_ed1 : gtl_yes {}; + + template <typename point_type_1, typename point_type_2> + typename enable_if< typename gtl_and_3<y_i_ed1, typename is_point_concept<typename geometry_concept<point_type_1>::type>::type, + typename is_point_concept<typename geometry_concept<point_type_2>::type>::type>::type, + typename point_difference_type<point_type_1>::type>::type + euclidean_distance(const point_type_1& point1, const point_type_2& point2, orientation_2d orient) { + typename coordinate_traits<typename point_traits<point_type_1>::coordinate_type>::coordinate_difference return_value = + get(point1, orient) - get(point2, orient); + return return_value < 0 ? (typename coordinate_traits<typename point_traits<point_type_1>::coordinate_type>::coordinate_difference)-return_value : return_value; + } + + struct y_i_ed2 : gtl_yes {}; + + template <typename point_type_1, typename point_type_2> + typename enable_if< typename gtl_and_3<y_i_ed2, typename gtl_same_type<point_concept, typename geometry_concept<point_type_1>::type>::type, + typename gtl_same_type<point_concept, typename geometry_concept<point_type_2>::type>::type>::type, + typename point_distance_type<point_type_1>::type>::type + euclidean_distance(const point_type_1& point1, const point_type_2& point2) { + typedef typename point_traits<point_type_1>::coordinate_type Unit; + return sqrt((double)(distance_squared(point1, point2))); + } + + template <typename point_type_1, typename point_type_2> + typename point_difference_type<point_type_1>::type + distance_squared(const point_type_1& point1, const point_type_2& point2, + typename enable_if< typename gtl_and<typename is_point_concept<typename geometry_concept<point_type_1>::type>::type, + typename is_point_concept<typename geometry_concept<point_type_2>::type>::type>::type>::type * = 0 + ) { + typedef typename point_traits<point_type_1>::coordinate_type Unit; + typename coordinate_traits<Unit>::coordinate_difference dx = euclidean_distance(point1, point2, HORIZONTAL); + typename coordinate_traits<Unit>::coordinate_difference dy = euclidean_distance(point1, point2, VERTICAL); + dx *= dx; + dy *= dy; + return dx + dy; + } + + template <typename point_type_1, typename point_type_2> + point_type_1 & + convolve(point_type_1& lvalue, const point_type_2& rvalue, + typename enable_if< typename gtl_and<typename is_mutable_point_concept<typename geometry_concept<point_type_1>::type>::type, + typename is_point_concept<typename geometry_concept<point_type_2>::type>::type>::type>::type * = 0 + ) { + x(lvalue, x(lvalue) + x(rvalue)); + y(lvalue, y(lvalue) + y(rvalue)); + return lvalue; + } + + template <typename point_type_1, typename point_type_2> + point_type_1 & + deconvolve(point_type_1& lvalue, const point_type_2& rvalue, + typename enable_if< typename gtl_and<typename is_mutable_point_concept<typename geometry_concept<point_type_1>::type>::type, + typename is_point_concept<typename geometry_concept<point_type_2>::type>::type>::type>::type * = 0 + ) { + x(lvalue, x(lvalue) - x(rvalue)); + y(lvalue, y(lvalue) - y(rvalue)); + return lvalue; + } + + template <typename point_type, typename coord_type> + point_type & + scale_up(point_type& point, coord_type factor, + typename enable_if<typename is_mutable_point_concept<typename geometry_concept<point_type>::type>::type>::type * = 0 + ) { + typedef typename point_traits<point_type>::coordinate_type Unit; + x(point, x(point) * (Unit)factor); + y(point, y(point) * (Unit)factor); + return point; + } + + template <typename point_type, typename coord_type> + point_type & + scale_down(point_type& point, coord_type factor, + typename enable_if<typename is_mutable_point_concept<typename geometry_concept<point_type>::type>::type>::type * = 0 + ) { + typedef typename point_traits<point_type>::coordinate_type Unit; + typedef typename coordinate_traits<Unit>::coordinate_distance dt; + x(point, scaling_policy<Unit>::round((dt)((dt)(x(point)) / (dt)factor))); + y(point, scaling_policy<Unit>::round((dt)((dt)(y(point)) / (dt)factor))); + return point; + } + + template <typename point_type, typename scaling_type> + point_type & + scale(point_type& point, + const scaling_type& scaling, + typename enable_if<typename is_mutable_point_concept<typename geometry_concept<point_type>::type>::type>::type * = 0 + ) { + typedef typename point_traits<point_type>::coordinate_type Unit; + Unit x_(x(point)), y_(y(point)); + scaling.scale(x_, y_); + x(point, x_); + y(point, y_); + return point; + } + + template <typename point_type, typename transformation_type> + point_type & + transform(point_type& point, const transformation_type& transformation, + typename enable_if<typename is_mutable_point_concept<typename geometry_concept<point_type>::type>::type>::type * = 0 + ) { + typedef typename point_traits<point_type>::coordinate_type Unit; + Unit x_(x(point)), y_(y(point)); + transformation.transform(x_, y_); + x(point, x_); + y(point, y_); + return point; + } + + struct y_pt_move : gtl_yes {}; + + template <typename point_type> + typename enable_if< + typename gtl_and< y_pt_move, + typename is_mutable_point_concept< + typename geometry_concept<point_type>::type>::type>::type, + point_type>::type & + move(point_type& point, orientation_2d orient, + typename point_traits<point_type>::coordinate_type displacement, + typename enable_if<typename is_mutable_point_concept<typename geometry_concept<point_type>::type>::type>::type * = 0 + ) { + typedef typename point_traits<point_type>::coordinate_type Unit; + Unit v(get(point, orient)); + set(point, orient, v + displacement); + return point; + } + + template <class T> + template <class T2> + point_data<T>& point_data<T>::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template <typename T> + struct geometry_concept<point_data<T> > { + typedef point_concept type; + }; +} +} +#endif + diff --git a/boost/polygon/point_data.hpp b/boost/polygon/point_data.hpp new file mode 100644 index 0000000000..d181b035d5 --- /dev/null +++ b/boost/polygon/point_data.hpp @@ -0,0 +1,105 @@ +/* + 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 GTLPOINT_DATA_HPP +#define GTLPOINT_DATA_HPP + +#include "isotropy.hpp" + +namespace boost { namespace polygon{ + + template <typename T> + class point_data { + public: + typedef T coordinate_type; + inline point_data() +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + {} + inline point_data(coordinate_type x, coordinate_type y) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { + coords_[HORIZONTAL] = x; coords_[VERTICAL] = y; + } + inline point_data(const point_data& that) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { (*this) = that; } + template <typename other> + point_data(const other& that) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { (*this) = that; } + inline point_data& operator=(const point_data& that) { + coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; return *this; + } + template<typename T1, typename T2> + inline point_data(const T1& x, const T2& y) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { + coords_[HORIZONTAL] = (coordinate_type)x; + coords_[VERTICAL] = (coordinate_type)y; + } + template <typename T2> + inline point_data(const point_data<T2>& rvalue) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { + coords_[HORIZONTAL] = (coordinate_type)(rvalue.x()); + coords_[VERTICAL] = (coordinate_type)(rvalue.y()); + } + template <typename T2> + inline point_data& operator=(const T2& rvalue); + inline bool operator==(const point_data& that) const { + return coords_[0] == that.coords_[0] && coords_[1] == that.coords_[1]; + } + inline bool operator!=(const point_data& that) const { + return !((*this) == that); + } + inline bool operator<(const point_data& that) const { + return coords_[0] < that.coords_[0] || + (coords_[0] == that.coords_[0] && coords_[1] < that.coords_[1]); + } + inline bool operator<=(const point_data& that) const { return !(that < *this); } + inline bool operator>(const point_data& that) const { return that < *this; } + inline bool operator>=(const point_data& that) const { return !((*this) < that); } + inline coordinate_type get(orientation_2d orient) const { + return coords_[orient.to_int()]; + } + inline void set(orientation_2d orient, coordinate_type value) { + coords_[orient.to_int()] = value; + } + inline coordinate_type x() const { + return coords_[HORIZONTAL]; + } + inline coordinate_type y() const { + return coords_[VERTICAL]; + } + inline point_data& x(coordinate_type value) { + coords_[HORIZONTAL] = value; + return *this; + } + inline point_data& y(coordinate_type value) { + coords_[VERTICAL] = value; + return *this; + } + private: + coordinate_type coords_[2]; + }; + +} +} +#endif + diff --git a/boost/polygon/point_traits.hpp b/boost/polygon/point_traits.hpp new file mode 100644 index 0000000000..504fa355f5 --- /dev/null +++ b/boost/polygon/point_traits.hpp @@ -0,0 +1,35 @@ +/* + 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_POINT_TRAITS_HPP +#define BOOST_POLYGON_POINT_TRAITS_HPP + +#include "isotropy.hpp" + +namespace boost { namespace polygon{ + template <typename T> + struct point_traits { + typedef typename T::coordinate_type coordinate_type; + + static inline coordinate_type get(const T& point, orientation_2d orient) { + return point.get(orient); + } + }; + + template <typename T> + struct point_mutable_traits { + static inline void set(T& point, orientation_2d orient, typename point_traits<T>::coordinate_type value) { + point.set(orient, value); + } + static inline T construct(typename point_traits<T>::coordinate_type x_value, typename point_traits<T>::coordinate_type y_value) { + return T(x_value, y_value); + } + }; +} +} +#endif + diff --git a/boost/polygon/polygon.hpp b/boost/polygon/polygon.hpp new file mode 100644 index 0000000000..4c3e43a5eb --- /dev/null +++ b/boost/polygon/polygon.hpp @@ -0,0 +1,91 @@ +/* + 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_POLYGON_HPP +#define BOOST_POLYGON_POLYGON_HPP +#define BOOST_POLYGON_VERSION 014401 + +#include "isotropy.hpp" + +//point +#include "point_data.hpp" +#include "point_traits.hpp" +#include "point_concept.hpp" + +//point 3d +#include "point_3d_data.hpp" +#include "point_3d_traits.hpp" +#include "point_3d_concept.hpp" + +#include "transform.hpp" +#include "detail/transform_detail.hpp" + +//interval +#include "interval_data.hpp" +#include "interval_traits.hpp" +#include "interval_concept.hpp" + +//rectangle +#include "rectangle_data.hpp" +#include "rectangle_traits.hpp" +#include "rectangle_concept.hpp" + +//algorithms needed by polygon types +#include "detail/iterator_points_to_compact.hpp" +#include "detail/iterator_compact_to_points.hpp" + +//polygons +#include "polygon_45_data.hpp" +#include "polygon_data.hpp" +#include "polygon_90_data.hpp" +#include "polygon_90_with_holes_data.hpp" +#include "polygon_45_with_holes_data.hpp" +#include "polygon_with_holes_data.hpp" +#include "polygon_traits.hpp" + +//manhattan boolean algorithms +#include "detail/boolean_op.hpp" +#include "detail/polygon_formation.hpp" +#include "detail/rectangle_formation.hpp" +#include "detail/max_cover.hpp" +#include "detail/property_merge.hpp" +#include "detail/polygon_90_touch.hpp" +#include "detail/iterator_geometry_to_set.hpp" + +//45 boolean op algorithms +#include "detail/boolean_op_45.hpp" +#include "detail/polygon_45_formation.hpp" + +//polygon set data types +#include "polygon_90_set_data.hpp" +//polygon set trait types +#include "polygon_90_set_traits.hpp" +//polygon set concepts +#include "polygon_90_set_concept.hpp" +//boolean operator syntax +#include "detail/polygon_90_set_view.hpp" + +//45 boolean op algorithms +#include "detail/polygon_45_touch.hpp" +#include "detail/property_merge_45.hpp" +#include "polygon_45_set_data.hpp" +#include "polygon_45_set_traits.hpp" +#include "polygon_45_set_concept.hpp" +#include "detail/polygon_45_set_view.hpp" + +//arbitrary polygon algorithms +#include "detail/polygon_arbitrary_formation.hpp" +#include "polygon_set_data.hpp" + +//general scanline +#include "detail/scan_arbitrary.hpp" +#include "polygon_set_traits.hpp" +#include "detail/polygon_set_view.hpp" + +#include "polygon_set_concept.hpp" + +#endif diff --git a/boost/polygon/polygon_45_data.hpp b/boost/polygon/polygon_45_data.hpp new file mode 100644 index 0000000000..86753ec13e --- /dev/null +++ b/boost/polygon/polygon_45_data.hpp @@ -0,0 +1,73 @@ +/* + 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_POLYGON_45_DATA_HPP +#define BOOST_POLYGON_POLYGON_45_DATA_HPP +#include "isotropy.hpp" +namespace boost { namespace polygon{ +struct polygon_45_concept; +template <typename T> class polygon_data; +template <typename T> +class polygon_45_data { +public: + typedef polygon_45_concept geometry_type; + typedef T coordinate_type; + typedef typename std::vector<point_data<coordinate_type> >::const_iterator iterator_type; + typedef typename coordinate_traits<T>::coordinate_distance area_type; + typedef point_data<T> point_type; + + inline polygon_45_data() : coords_() {} //do nothing default constructor + + template<class iT> + inline polygon_45_data(iT input_begin, iT input_end) : coords_(input_begin, input_end) {} + + template<class iT> + inline polygon_45_data& set(iT input_begin, iT input_end) { + coords_.clear(); //just in case there was some old data there + coords_.insert(coords_.end(), input_begin, input_end); + return *this; + } + + // copy constructor (since we have dynamic memory) + inline polygon_45_data(const polygon_45_data& that) : coords_(that.coords_) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline polygon_45_data& operator=(const polygon_45_data& that) { + coords_ = that.coords_; + return *this; + } + + template <typename T2> + inline polygon_45_data& operator=(const T2& rvalue); + + inline bool operator==(const polygon_45_data& that) const { + if(coords_.size() != that.coords_.size()) return false; + for(std::size_t i = 0; i < coords_.size(); ++i) { + if(coords_[i] != that.coords_[i]) return false; + } + return true; + } + + inline bool operator!=(const polygon_45_data& that) const { return !((*this) == that); } + + // get begin iterator, returns a pointer to a const Unit + inline iterator_type begin() const { return coords_.begin(); } + + // get end iterator, returns a pointer to a const Unit + inline iterator_type end() const { return coords_.end(); } + + inline std::size_t size() const { return coords_.size(); } + +public: + std::vector<point_data<coordinate_type> > coords_; +}; + + +} +} +#endif + diff --git a/boost/polygon/polygon_45_set_concept.hpp b/boost/polygon/polygon_45_set_concept.hpp new file mode 100644 index 0000000000..f22910cb90 --- /dev/null +++ b/boost/polygon/polygon_45_set_concept.hpp @@ -0,0 +1,441 @@ +/* + 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_POLYGON_45_SET_CONCEPT_HPP +#define BOOST_POLYGON_POLYGON_45_SET_CONCEPT_HPP +#include "polygon_45_set_data.hpp" +#include "polygon_45_set_traits.hpp" +#include "detail/polygon_45_touch.hpp" +namespace boost { namespace polygon{ + + template <typename T, typename T2> + struct is_either_polygon_45_set_type { + typedef typename gtl_or<typename is_polygon_45_set_type<T>::type, typename is_polygon_45_set_type<T2>::type >::type type; + }; + + template <typename T> + struct is_polygon_45_or_90_set_type { + typedef typename gtl_or<typename is_polygon_45_set_type<T>::type, typename is_polygon_90_set_type<T>::type >::type type; + }; + + template <typename polygon_set_type> + typename enable_if< typename gtl_if<typename is_polygon_45_or_90_set_type<polygon_set_type>::type>::type, + typename polygon_45_set_traits<polygon_set_type>::iterator_type>::type + begin_45_set_data(const polygon_set_type& polygon_set) { + return polygon_45_set_traits<polygon_set_type>::begin(polygon_set); + } + + template <typename polygon_set_type> + typename enable_if< typename gtl_if<typename is_polygon_45_or_90_set_type<polygon_set_type>::type>::type, + typename polygon_45_set_traits<polygon_set_type>::iterator_type>::type + end_45_set_data(const polygon_set_type& polygon_set) { + return polygon_45_set_traits<polygon_set_type>::end(polygon_set); + } + + template <typename polygon_set_type> + typename enable_if< typename gtl_if<typename is_polygon_45_set_type<polygon_set_type>::type>::type, + bool>::type + clean(const polygon_set_type& polygon_set) { + return polygon_45_set_traits<polygon_set_type>::clean(polygon_set); + } + + //assign + template <typename polygon_set_type_1, typename polygon_set_type_2> + typename enable_if< typename gtl_and< typename gtl_if<typename is_mutable_polygon_45_set_type<polygon_set_type_1>::type>::type, + typename gtl_if<typename is_polygon_45_or_90_set_type<polygon_set_type_2>::type>::type>::type, + polygon_set_type_1>::type & + assign(polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { + polygon_45_set_mutable_traits<polygon_set_type_1>::set(lvalue, begin_45_set_data(rvalue), end_45_set_data(rvalue)); + return lvalue; + } + + //get trapezoids + template <typename output_container_type, typename polygon_set_type> + typename enable_if< typename gtl_if<typename is_polygon_45_set_type<polygon_set_type>::type>::type, + void>::type + get_trapezoids(output_container_type& output, const polygon_set_type& polygon_set) { + clean(polygon_set); + polygon_45_set_data<typename polygon_45_set_traits<polygon_set_type>::coordinate_type> ps; + assign(ps, polygon_set); + ps.get_trapezoids(output); + } + + //get trapezoids + template <typename output_container_type, typename polygon_set_type> + typename enable_if< typename gtl_if<typename is_polygon_45_set_type<polygon_set_type>::type>::type, + void>::type + get_trapezoids(output_container_type& output, const polygon_set_type& polygon_set, orientation_2d slicing_orientation) { + clean(polygon_set); + polygon_45_set_data<typename polygon_45_set_traits<polygon_set_type>::coordinate_type> ps; + assign(ps, polygon_set); + ps.get_trapezoids(output, slicing_orientation); + } + + //equivalence + template <typename polygon_set_type_1, typename polygon_set_type_2> + typename enable_if< typename gtl_and_3<typename gtl_if<typename is_polygon_45_or_90_set_type<polygon_set_type_1>::type>::type, + typename gtl_if<typename is_polygon_45_or_90_set_type<polygon_set_type_2>::type>::type, + typename gtl_if<typename is_either_polygon_45_set_type<polygon_set_type_1, + polygon_set_type_2>::type>::type>::type, + bool>::type + equivalence(const polygon_set_type_1& lvalue, + const polygon_set_type_2& rvalue) { + polygon_45_set_data<typename polygon_45_set_traits<polygon_set_type_1>::coordinate_type> ps1; + assign(ps1, lvalue); + polygon_45_set_data<typename polygon_45_set_traits<polygon_set_type_2>::coordinate_type> ps2; + assign(ps2, rvalue); + return ps1 == ps2; + } + + //clear + template <typename polygon_set_type> + typename enable_if< typename gtl_if<typename is_mutable_polygon_45_set_type<polygon_set_type>::type>::type, + void>::type + clear(polygon_set_type& polygon_set) { + polygon_45_set_data<typename polygon_45_set_traits<polygon_set_type>::coordinate_type> ps; + assign(polygon_set, ps); + } + + //empty + template <typename polygon_set_type> + typename enable_if< typename gtl_if<typename is_mutable_polygon_45_set_type<polygon_set_type>::type>::type, + bool>::type + empty(const polygon_set_type& polygon_set) { + if(clean(polygon_set)) return begin_45_set_data(polygon_set) == end_45_set_data(polygon_set); + polygon_45_set_data<typename polygon_45_set_traits<polygon_set_type>::coordinate_type> ps; + assign(ps, polygon_set); + ps.clean(); + return ps.empty(); + } + + //extents + template <typename polygon_set_type, typename rectangle_type> + typename enable_if< + typename gtl_and< typename gtl_if<typename is_mutable_polygon_45_set_type<polygon_set_type>::type>::type, + typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + bool>::type + extents(rectangle_type& extents_rectangle, + const polygon_set_type& polygon_set) { + clean(polygon_set); + polygon_45_set_data<typename polygon_45_set_traits<polygon_set_type>::coordinate_type> ps; + assign(ps, polygon_set); + return ps.extents(extents_rectangle); + } + + //area + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, + typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::area_type>::type + area(const polygon_set_type& polygon_set) { + typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; + typedef polygon_45_with_holes_data<Unit> p_type; + typedef typename coordinate_traits<Unit>::area_type area_type; + std::vector<p_type> polys; + assign(polys, polygon_set); + area_type retval = (area_type)0; + for(std::size_t i = 0; i < polys.size(); ++i) { + retval += area(polys[i]); + } + return retval; + } + + //interact + template <typename polygon_set_type_1, typename polygon_set_type_2> + typename enable_if < + typename gtl_and< typename gtl_if<typename is_mutable_polygon_45_set_type<polygon_set_type_1>::type>::type, + typename gtl_if<typename is_polygon_45_or_90_set_type<polygon_set_type_2>::type>::type >::type, + polygon_set_type_1>::type& + interact(polygon_set_type_1& polygon_set_1, const polygon_set_type_2& polygon_set_2) { + typedef typename polygon_45_set_traits<polygon_set_type_1>::coordinate_type Unit; + std::vector<polygon_45_data<Unit> > polys; + assign(polys, polygon_set_1); + std::vector<std::set<int> > graph(polys.size()+1, std::set<int>()); + connectivity_extraction_45<Unit> ce; + ce.insert(polygon_set_2); + for(std::size_t i = 0; i < polys.size(); ++i){ + ce.insert(polys[i]); + } + ce.extract(graph); + clear(polygon_set_1); + polygon_45_set_data<Unit> ps; + for(std::set<int>::iterator itr = graph[0].begin(); itr != graph[0].end(); ++itr){ + ps.insert(polys[(*itr)-1]); + } + assign(polygon_set_1, ps); + return polygon_set_1; + } + +// //self_intersect +// template <typename polygon_set_type> +// typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type>::type, +// polygon_set_type>::type & +// self_intersect(polygon_set_type& polygon_set) { +// typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; +// //TODO +// } + + template <typename polygon_set_type, typename coord_type> + typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, + polygon_set_type>::type & + resize(polygon_set_type& polygon_set, coord_type resizing, + RoundingOption rounding = CLOSEST, CornerOption corner = INTERSECTION) { + typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; + clean(polygon_set); + polygon_45_set_data<Unit> ps; + assign(ps, polygon_set); + ps.resize(resizing, rounding, corner); + assign(polygon_set, ps); + return polygon_set; + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, + polygon_set_type>::type & + bloat(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { + return resize(polygon_set, static_cast<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>(bloating)); + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, + polygon_set_type>::type & + shrink(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type shrinking) { + return resize(polygon_set, -(typename polygon_45_set_traits<polygon_set_type>::coordinate_type)shrinking); + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, + polygon_set_type>::type & + grow_and(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { + typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; + std::vector<polygon_45_data<Unit> > polys; + assign(polys, polygon_set); + clear(polygon_set); + polygon_45_set_data<Unit> ps; + for(std::size_t i = 0; i < polys.size(); ++i) { + polygon_45_set_data<Unit> tmpPs; + tmpPs.insert(polys[i]); + bloat(tmpPs, bloating); + tmpPs.clean(); //apply implicit OR on tmp polygon set + ps.insert(tmpPs); + } + ps.self_intersect(); + assign(polygon_set, ps); + return polygon_set; + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, + polygon_set_type>::type & + scale_up(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type factor) { + typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; + clean(polygon_set); + polygon_45_set_data<Unit> ps; + assign(ps, polygon_set); + ps.scale_up(factor); + assign(polygon_set, ps); + return polygon_set; + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, + polygon_set_type>::type & + scale_down(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type factor) { + typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; + clean(polygon_set); + polygon_45_set_data<Unit> ps; + assign(ps, polygon_set); + ps.scale_down(factor); + assign(polygon_set, ps); + return polygon_set; + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, + polygon_set_type>::type & + scale(polygon_set_type& polygon_set, double factor) { + typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; + clean(polygon_set); + polygon_45_set_data<Unit> ps; + assign(ps, polygon_set); + ps.scale(factor); + assign(polygon_set, ps); + return polygon_set; + } + + //self_intersect + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, + polygon_set_type>::type & + self_intersect(polygon_set_type& polygon_set) { + typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; + polygon_45_set_data<Unit> ps; + assign(ps, polygon_set); + ps.self_intersect(); + assign(polygon_set, ps); + return polygon_set; + } + + //self_xor + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, + polygon_set_type>::type & + self_xor(polygon_set_type& polygon_set) { + typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; + polygon_45_set_data<Unit> ps; + assign(ps, polygon_set); + ps.self_xor(); + assign(polygon_set, ps); + return polygon_set; + } + + //transform + template <typename polygon_set_type, typename transformation_type> + typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, + polygon_set_type>::type & + transform(polygon_set_type& polygon_set, + const transformation_type& transformation) { + typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; + clean(polygon_set); + polygon_45_set_data<Unit> ps; + assign(ps, polygon_set); + ps.transform(transformation); + assign(polygon_set, ps); + return polygon_set; + } + + //keep + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_45_set_type<polygon_set_type>::type, + polygon_set_type>::type & + keep(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::area_type min_area, + typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::area_type max_area, + typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type min_width, + typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type max_width, + typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type min_height, + typename coordinate_traits<typename polygon_45_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type max_height) { + typedef typename polygon_45_set_traits<polygon_set_type>::coordinate_type Unit; + typedef typename coordinate_traits<Unit>::unsigned_area_type uat; + std::list<polygon_45_data<Unit> > polys; + assign(polys, polygon_set); + typename std::list<polygon_45_data<Unit> >::iterator itr_nxt; + for(typename std::list<polygon_45_data<Unit> >::iterator itr = polys.begin(); itr != polys.end(); itr = itr_nxt){ + itr_nxt = itr; + ++itr_nxt; + rectangle_data<Unit> bbox; + extents(bbox, *itr); + uat pwidth = delta(bbox, HORIZONTAL); + if(pwidth > min_width && pwidth <= max_width){ + uat pheight = delta(bbox, VERTICAL); + if(pheight > min_height && pheight <= max_height){ + typename coordinate_traits<Unit>::area_type parea = area(*itr); + if(parea <= max_area && parea >= min_area) { + continue; + } + } + } + polys.erase(itr); + } + assign(polygon_set, polys); + return polygon_set; + } + + template <typename T> + struct view_of<polygon_90_set_concept, T> { + typedef typename get_coordinate_type<T, typename geometry_concept<T>::type >::type coordinate_type; + T* tp; + std::vector<polygon_90_with_holes_data<coordinate_type> > polys; + view_of(T& obj) : tp(&obj), polys() { + std::vector<polygon_with_holes_data<coordinate_type> > gpolys; + assign(gpolys, obj); + for(typename std::vector<polygon_with_holes_data<coordinate_type> >::iterator itr = gpolys.begin(); + itr != gpolys.end(); ++itr) { + polys.push_back(polygon_90_with_holes_data<coordinate_type>()); + assign(polys.back(), view_as<polygon_90_with_holes_concept>(*itr)); + } + } + view_of(const T& obj) : tp(), polys() { + std::vector<polygon_with_holes_data<coordinate_type> > gpolys; + assign(gpolys, obj); + for(typename std::vector<polygon_with_holes_data<coordinate_type> >::iterator itr = gpolys.begin(); + itr != gpolys.end(); ++itr) { + polys.push_back(polygon_90_with_holes_data<coordinate_type>()); + assign(polys.back(), view_as<polygon_90_with_holes_concept>(*itr)); + } + } + + typedef typename std::vector<polygon_90_with_holes_data<coordinate_type> >::const_iterator iterator_type; + typedef view_of operator_arg_type; + + inline iterator_type begin() const { + return polys.begin(); + } + + inline iterator_type end() const { + return polys.end(); + } + + inline orientation_2d orient() const { return HORIZONTAL; } + + inline bool clean() const { return false; } + + inline bool sorted() const { return false; } + + inline T& get() { return *tp; } + + }; + + template <typename T> + struct polygon_90_set_traits<view_of<polygon_90_set_concept, T> > { + typedef typename view_of<polygon_90_set_concept, T>::coordinate_type coordinate_type; + typedef typename view_of<polygon_90_set_concept, T>::iterator_type iterator_type; + typedef view_of<polygon_90_set_concept, T> operator_arg_type; + + static inline iterator_type begin(const view_of<polygon_90_set_concept, T>& polygon_set) { + return polygon_set.begin(); + } + + static inline iterator_type end(const view_of<polygon_90_set_concept, T>& polygon_set) { + return polygon_set.end(); + } + + static inline orientation_2d orient(const view_of<polygon_90_set_concept, T>& polygon_set) { + return polygon_set.orient(); } + + static inline bool clean(const view_of<polygon_90_set_concept, T>& polygon_set) { + return polygon_set.clean(); } + + static inline bool sorted(const view_of<polygon_90_set_concept, T>& polygon_set) { + return polygon_set.sorted(); } + + }; + + template <typename T> + struct geometry_concept<view_of<polygon_90_set_concept, T> > { + typedef polygon_90_set_concept type; + }; + + template <typename T> + struct get_coordinate_type<view_of<polygon_90_set_concept, T>, polygon_90_set_concept> { + typedef typename view_of<polygon_90_set_concept, T>::coordinate_type type; + }; + template <typename T> + struct get_iterator_type_2<view_of<polygon_90_set_concept, T>, polygon_90_set_concept> { + typedef typename view_of<polygon_90_set_concept, T>::iterator_type type; + static type begin(const view_of<polygon_90_set_concept, T>& t) { return t.begin(); } + static type end(const view_of<polygon_90_set_concept, T>& t) { return t.end(); } + }; + +} +} +#include "detail/polygon_45_set_view.hpp" +#endif diff --git a/boost/polygon/polygon_45_set_data.hpp b/boost/polygon/polygon_45_set_data.hpp new file mode 100644 index 0000000000..e541ee5cbf --- /dev/null +++ b/boost/polygon/polygon_45_set_data.hpp @@ -0,0 +1,1877 @@ +/* + 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_POLYGON_45_SET_DATA_HPP +#define BOOST_POLYGON_POLYGON_45_SET_DATA_HPP +#include "polygon_90_set_data.hpp" +#include "detail/boolean_op_45.hpp" +#include "detail/polygon_45_formation.hpp" +#include "detail/polygon_45_touch.hpp" +#include "detail/property_merge_45.hpp" +namespace boost { namespace polygon{ + + enum RoundingOption { CLOSEST = 0, OVERSIZE = 1, UNDERSIZE = 2, SQRT2 = 3, SQRT1OVER2 = 4 }; + enum CornerOption { INTERSECTION = 0, ORTHOGONAL = 1, UNFILLED = 2 }; + + template <typename ltype, typename rtype, int op_type> + class polygon_45_set_view; + + struct polygon_45_set_concept {}; + + template <typename Unit> + class polygon_45_set_data { + public: + typedef typename polygon_45_formation<Unit>::Vertex45Compact Vertex45Compact; + typedef std::vector<Vertex45Compact> Polygon45VertexData; + + typedef Unit coordinate_type; + typedef Polygon45VertexData value_type; + typedef typename value_type::const_iterator iterator_type; + typedef polygon_45_set_data operator_arg_type; + + // default constructor + inline polygon_45_set_data() : error_data_(), data_(), dirty_(false), unsorted_(false), is_manhattan_(true) {} + + // constructor from a geometry object + template <typename geometry_type> + inline polygon_45_set_data(const geometry_type& that) : error_data_(), data_(), dirty_(false), unsorted_(false), is_manhattan_(true) { + insert(that); + } + + // copy constructor + inline polygon_45_set_data(const polygon_45_set_data& that) : + error_data_(that.error_data_), data_(that.data_), dirty_(that.dirty_), + unsorted_(that.unsorted_), is_manhattan_(that.is_manhattan_) {} + + template <typename ltype, typename rtype, int op_type> + inline polygon_45_set_data(const polygon_45_set_view<ltype, rtype, op_type>& that) : + error_data_(), data_(), dirty_(false), unsorted_(false), is_manhattan_(true) { + (*this) = that.value(); + } + + // destructor + inline ~polygon_45_set_data() {} + + // assignement operator + inline polygon_45_set_data& operator=(const polygon_45_set_data& that) { + if(this == &that) return *this; + error_data_ = that.error_data_; + data_ = that.data_; + dirty_ = that.dirty_; + unsorted_ = that.unsorted_; + is_manhattan_ = that.is_manhattan_; + return *this; + } + + template <typename ltype, typename rtype, int op_type> + inline polygon_45_set_data& operator=(const polygon_45_set_view<ltype, rtype, op_type>& that) { + (*this) = that.value(); + return *this; + } + + template <typename geometry_object> + inline polygon_45_set_data& operator=(const geometry_object& geometry) { + data_.clear(); + insert(geometry); + return *this; + } + + // insert iterator range + inline void insert(iterator_type input_begin, iterator_type input_end, bool is_hole = false) { + if(input_begin == input_end || (!data_.empty() && &(*input_begin) == &(*(data_.begin())))) return; + dirty_ = true; + unsorted_ = true; + while(input_begin != input_end) { + insert(*input_begin, is_hole); + ++input_begin; + } + } + + // insert iterator range + template <typename iT> + inline void insert(iT input_begin, iT input_end, bool is_hole = false) { + if(input_begin == input_end) return; + dirty_ = true; + unsorted_ = true; + while(input_begin != input_end) { + insert(*input_begin, is_hole); + ++input_begin; + } + } + + inline void insert(const polygon_45_set_data& polygon_set, bool is_hole = false); + template <typename coord_type> + inline void insert(const polygon_45_set_data<coord_type>& polygon_set, bool is_hole = false); + + template <typename geometry_type> + inline void insert(const geometry_type& geometry_object, bool is_hole = false) { + insert_dispatch(geometry_object, is_hole, typename geometry_concept<geometry_type>::type()); + } + + inline void insert_clean(const Vertex45Compact& vertex_45, bool is_hole = false) { + if(vertex_45.count.is_45()) is_manhattan_ = false; + data_.push_back(vertex_45); + if(is_hole) data_.back().count.invert(); + } + + inline void insert(const Vertex45Compact& vertex_45, bool is_hole = false) { + dirty_ = true; + unsorted_ = true; + insert_clean(vertex_45, is_hole); + } + + template <typename coordinate_type_2> + inline void insert(const polygon_90_set_data<coordinate_type_2>& polygon_set, bool is_hole = false) { + if(polygon_set.orient() == VERTICAL) { + for(typename polygon_90_set_data<coordinate_type_2>::iterator_type itr = polygon_set.begin(); + itr != polygon_set.end(); ++itr) { + Vertex45Compact vertex_45(point_data<Unit>((*itr).first, (*itr).second.first), 2, (*itr).second.second); + vertex_45.count[1] = (*itr).second.second; + if(is_hole) vertex_45.count[1] *= - 1; + insert_clean(vertex_45, is_hole); + } + } else { + for(typename polygon_90_set_data<coordinate_type_2>::iterator_type itr = polygon_set.begin(); + itr != polygon_set.end(); ++itr) { + Vertex45Compact vertex_45(point_data<Unit>((*itr).second.first, (*itr).first), 2, (*itr).second.second); + vertex_45.count[1] = (*itr).second.second; + if(is_hole) vertex_45.count[1] *= - 1; + insert_clean(vertex_45, is_hole); + } + } + dirty_ = true; + unsorted_ = true; + } + + template <typename output_container> + inline void get(output_container& output) const { + get_dispatch(output, typename geometry_concept<typename output_container::value_type>::type()); + } + + inline bool has_error_data() const { return !error_data_.empty(); } + inline std::size_t error_count() const { return error_data_.size() / 4; } + inline void get_error_data(polygon_45_set_data& p) const { + p.data_.insert(p.data_.end(), error_data_.begin(), error_data_.end()); + } + + // equivalence operator + inline bool operator==(const polygon_45_set_data& p) const { + clean(); + p.clean(); + return data_ == p.data_; + } + + // inequivalence operator + inline bool operator!=(const polygon_45_set_data& p) const { + return !((*this) == p); + } + + // get iterator to begin vertex data + inline iterator_type begin() const { + return data_.begin(); + } + + // get iterator to end vertex data + inline iterator_type end() const { + return data_.end(); + } + + const value_type& value() const { + return data_; + } + + // clear the contents of the polygon_45_set_data + inline void clear() { data_.clear(); error_data_.clear(); dirty_ = unsorted_ = false; is_manhattan_ = true; } + + // find out if Polygon set is empty + inline bool empty() const { return data_.empty(); } + + // get the Polygon set size in vertices + inline std::size_t size() const { clean(); return data_.size(); } + + // get the current Polygon set capacity in vertices + inline std::size_t capacity() const { return data_.capacity(); } + + // reserve size of polygon set in vertices + inline void reserve(std::size_t size) { return data_.reserve(size); } + + // find out if Polygon set is sorted + inline bool sorted() const { return !unsorted_; } + + // find out if Polygon set is clean + inline bool dirty() const { return dirty_; } + + // find out if Polygon set is clean + inline bool is_manhattan() const { return is_manhattan_; } + + bool clean() const; + + void sort() const{ + if(unsorted_) { + gtlsort(data_.begin(), data_.end()); + unsorted_ = false; + } + } + + template <typename input_iterator_type> + void set(input_iterator_type input_begin, input_iterator_type input_end) { + data_.clear(); + insert(input_begin, input_end); + dirty_ = true; + unsorted_ = true; + } + + void set_clean(const value_type& value) { + data_ = value; + dirty_ = false; + unsorted_ = false; + } + + void set(const value_type& value) { + data_ = value; + dirty_ = true; + unsorted_ = true; + } + + // append to the container cT with polygons (holes will be fractured vertically) + template <class cT> + void get_polygons(cT& container) const { + get_dispatch(container, polygon_45_concept()); + } + + // append to the container cT with PolygonWithHoles objects + template <class cT> + void get_polygons_with_holes(cT& container) const { + get_dispatch(container, polygon_45_with_holes_concept()); + } + + // append to the container cT with polygons of three or four verticies + // slicing orientation is vertical + template <class cT> + void get_trapezoids(cT& container) const { + clean(); + typename polygon_45_formation<Unit>::Polygon45Tiling pf; + //std::cout << "FORMING POLYGONS\n"; + pf.scan(container, data_.begin(), data_.end()); + //std::cout << "DONE FORMING POLYGONS\n"; + } + + // append to the container cT with polygons of three or four verticies + template <class cT> + void get_trapezoids(cT& container, orientation_2d slicing_orientation) const { + if(slicing_orientation == VERTICAL) { + get_trapezoids(container); + } else { + polygon_45_set_data<Unit> ps(*this); + ps.transform(axis_transformation(axis_transformation::SWAP_XY)); + cT result; + ps.get_trapezoids(result); + for(typename cT::iterator itr = result.begin(); itr != result.end(); ++itr) { + ::boost::polygon::transform(*itr, axis_transformation(axis_transformation::SWAP_XY)); + } + container.insert(container.end(), result.begin(), result.end()); + } + } + + // insert vertex sequence + template <class iT> + void insert_vertex_sequence(iT begin_vertex, iT end_vertex, + direction_1d winding, bool is_hole = false); + + // get the external boundary rectangle + template <typename rectangle_type> + bool extents(rectangle_type& rect) const; + + // snap verticies of set to even,even or odd,odd coordinates + void snap() const; + + // |= &= += *= -= ^= binary operators + polygon_45_set_data& operator|=(const polygon_45_set_data& b); + polygon_45_set_data& operator&=(const polygon_45_set_data& b); + polygon_45_set_data& operator+=(const polygon_45_set_data& b); + polygon_45_set_data& operator*=(const polygon_45_set_data& b); + polygon_45_set_data& operator-=(const polygon_45_set_data& b); + polygon_45_set_data& operator^=(const polygon_45_set_data& b); + + // resizing operations + polygon_45_set_data& operator+=(Unit delta); + polygon_45_set_data& operator-=(Unit delta); + + // shrink the Polygon45Set by shrinking + polygon_45_set_data& resize(coordinate_type resizing, RoundingOption rounding = CLOSEST, + CornerOption corner = INTERSECTION); + + // transform set + template <typename transformation_type> + polygon_45_set_data& transform(const transformation_type& tr); + + // scale set + polygon_45_set_data& scale_up(typename coordinate_traits<Unit>::unsigned_area_type factor); + polygon_45_set_data& scale_down(typename coordinate_traits<Unit>::unsigned_area_type factor); + polygon_45_set_data& scale(double scaling); + + // self_intersect + polygon_45_set_data& self_intersect() { + sort(); + applyAdaptiveUnary_<1>(); //1 = AND + dirty_ = false; + return *this; + } + + // self_xor + polygon_45_set_data& self_xor() { + sort(); + applyAdaptiveUnary_<3>(); //3 = XOR + dirty_ = false; + return *this; + } + + // accumulate the bloated polygon + template <typename geometry_type> + polygon_45_set_data& insert_with_resize(const geometry_type& poly, + coordinate_type resizing, RoundingOption rounding = CLOSEST, + CornerOption corner = INTERSECTION, + bool hole = false) { + return insert_with_resize_dispatch(poly, resizing, rounding, corner, hole, typename geometry_concept<geometry_type>::type()); + } + + private: + mutable value_type error_data_; + mutable value_type data_; + mutable bool dirty_; + mutable bool unsorted_; + mutable bool is_manhattan_; + + private: + //functions + template <typename output_container> + void get_dispatch(output_container& output, polygon_45_concept tag) const { + get_fracture(output, true, tag); + } + template <typename output_container> + void get_dispatch(output_container& output, polygon_45_with_holes_concept tag) const { + get_fracture(output, false, tag); + } + template <typename output_container> + void get_dispatch(output_container& output, polygon_concept tag) const { + get_fracture(output, true, tag); + } + template <typename output_container> + void get_dispatch(output_container& output, polygon_with_holes_concept tag) const { + get_fracture(output, false, tag); + } + template <typename output_container, typename concept_type> + void get_fracture(output_container& container, bool fracture_holes, concept_type ) const { + clean(); + typename polygon_45_formation<Unit>::Polygon45Formation pf(fracture_holes); + //std::cout << "FORMING POLYGONS\n"; + pf.scan(container, data_.begin(), data_.end()); + } + + template <typename geometry_type> + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, undefined_concept) { + insert(geometry_object.begin(), geometry_object.end(), is_hole); + } + template <typename geometry_type> + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, rectangle_concept tag); + template <typename geometry_type> + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_90_concept ) { + insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole); + } + template <typename geometry_type> + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_90_with_holes_concept ) { + insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole); + for(typename polygon_with_holes_traits<geometry_type>::iterator_holes_type itr = + begin_holes(geometry_object); itr != end_holes(geometry_object); + ++itr) { + insert_vertex_sequence(begin_points(*itr), end_points(*itr), winding(*itr), !is_hole); + } + } + template <typename geometry_type> + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_45_concept ) { + insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole); + } + template <typename geometry_type> + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_45_with_holes_concept ) { + insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole); + for(typename polygon_with_holes_traits<geometry_type>::iterator_holes_type itr = + begin_holes(geometry_object); itr != end_holes(geometry_object); + ++itr) { + insert_vertex_sequence(begin_points(*itr), end_points(*itr), winding(*itr), !is_hole); + } + } + template <typename geometry_type> + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_45_set_concept ) { + polygon_45_set_data ps; + assign(ps, geometry_object); + insert(ps, is_hole); + } + template <typename geometry_type> + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_90_set_concept ) { + std::list<polygon_90_data<coordinate_type> > pl; + assign(pl, geometry_object); + insert(pl.begin(), pl.end(), is_hole); + } + + void insert_vertex_half_edge_45_pair(const point_data<Unit>& pt1, point_data<Unit>& pt2, + const point_data<Unit>& pt3, direction_1d wdir); + + template <typename geometry_type> + polygon_45_set_data& insert_with_resize_dispatch(const geometry_type& poly, + coordinate_type resizing, RoundingOption rounding, + CornerOption corner, bool hole, polygon_45_concept tag); + + // accumulate the bloated polygon with holes + template <typename geometry_type> + polygon_45_set_data& insert_with_resize_dispatch(const geometry_type& poly, + coordinate_type resizing, RoundingOption rounding, + CornerOption corner, bool hole, polygon_45_with_holes_concept tag); + + static void snap_vertex_45(Vertex45Compact& vertex); + + public: + template <int op> + void applyAdaptiveBoolean_(const polygon_45_set_data& rvalue) const; + template <int op> + void applyAdaptiveBoolean_(polygon_45_set_data& result, const polygon_45_set_data& rvalue) const; + template <int op> + void applyAdaptiveUnary_() const; + }; + + template <typename T> + struct geometry_concept<polygon_45_set_data<T> > { + typedef polygon_45_set_concept type; + }; + + template <typename iT, typename T> + void scale_up_vertex_45_compact_range(iT beginr, iT endr, T factor) { + for( ; beginr != endr; ++beginr) { + scale_up((*beginr).pt, factor); + } + } + template <typename iT, typename T> + void scale_down_vertex_45_compact_range_blindly(iT beginr, iT endr, T factor) { + for( ; beginr != endr; ++beginr) { + scale_down((*beginr).pt, factor); + } + } + + template <typename Unit> + inline std::pair<int, int> characterizeEdge45(const point_data<Unit>& pt1, const point_data<Unit>& pt2) { + std::pair<int, int> retval(0, 1); + if(pt1.x() == pt2.x()) { + retval.first = 3; + retval.second = -1; + return retval; + } + //retval.second = pt1.x() < pt2.x() ? -1 : 1; + retval.second = 1; + if(pt1.y() == pt2.y()) { + retval.first = 1; + } else if(pt1.x() < pt2.x()) { + if(pt1.y() < pt2.y()) { + retval.first = 2; + } else { + retval.first = 0; + } + } else { + if(pt1.y() < pt2.y()) { + retval.first = 0; + } else { + retval.first = 2; + } + } + return retval; + } + + template <typename cT, typename pT> + bool insert_vertex_half_edge_45_pair_into_vector(cT& output, + const pT& pt1, pT& pt2, + const pT& pt3, + direction_1d wdir) { + int multiplier = wdir == LOW ? -1 : 1; + typename cT::value_type vertex(pt2, 0, 0); + //std::cout << pt1 << " " << pt2 << " " << pt3 << std::endl; + std::pair<int, int> check; + check = characterizeEdge45(pt1, pt2); + //std::cout << "index " << check.first << " " << check.second * -multiplier << std::endl; + vertex.count[check.first] += check.second * -multiplier; + check = characterizeEdge45(pt2, pt3); + //std::cout << "index " << check.first << " " << check.second * multiplier << std::endl; + vertex.count[check.first] += check.second * multiplier; + output.push_back(vertex); + return vertex.count.is_45(); + } + + template <typename Unit> + inline void polygon_45_set_data<Unit>::insert_vertex_half_edge_45_pair(const point_data<Unit>& pt1, point_data<Unit>& pt2, + const point_data<Unit>& pt3, + direction_1d wdir) { + if(insert_vertex_half_edge_45_pair_into_vector(data_, pt1, pt2, pt3, wdir)) is_manhattan_ = false; + } + + template <typename Unit> + template <class iT> + inline void polygon_45_set_data<Unit>::insert_vertex_sequence(iT begin_vertex, iT end_vertex, + direction_1d winding, bool is_hole) { + if(begin_vertex == end_vertex) return; + if(is_hole) winding = winding.backward(); + iT itr = begin_vertex; + if(itr == end_vertex) return; + point_data<Unit> firstPt = *itr; + ++itr; + point_data<Unit> secondPt(firstPt); + //skip any duplicate points + do { + if(itr == end_vertex) return; + secondPt = *itr; + ++itr; + } while(secondPt == firstPt); + point_data<Unit> prevPt = secondPt; + point_data<Unit> prevPrevPt = firstPt; + while(itr != end_vertex) { + point_data<Unit> pt = *itr; + //skip any duplicate points + if(pt == prevPt) { + ++itr; + continue; + } + //operate on the three points + insert_vertex_half_edge_45_pair(prevPrevPt, prevPt, pt, winding); + prevPrevPt = prevPt; + prevPt = pt; + ++itr; + } + if(prevPt != firstPt) { + insert_vertex_half_edge_45_pair(prevPrevPt, prevPt, firstPt, winding); + insert_vertex_half_edge_45_pair(prevPt, firstPt, secondPt, winding); + } else { + insert_vertex_half_edge_45_pair(prevPrevPt, firstPt, secondPt, winding); + } + dirty_ = true; + unsorted_ = true; + } + + // insert polygon set + template <typename Unit> + inline void polygon_45_set_data<Unit>::insert(const polygon_45_set_data<Unit>& polygon_set, bool is_hole) { + std::size_t count = data_.size(); + data_.insert(data_.end(), polygon_set.data_.begin(), polygon_set.data_.end()); + error_data_.insert(error_data_.end(), polygon_set.error_data_.begin(), + polygon_set.error_data_.end()); + if(is_hole) { + for(std::size_t i = count; i < data_.size(); ++i) { + data_[i].count = data_[i].count.invert(); + } + } + dirty_ = true; + unsorted_ = true; + if(polygon_set.is_manhattan_ == false) is_manhattan_ = false; + return; + } + // insert polygon set + template <typename Unit> + template <typename coord_type> + inline void polygon_45_set_data<Unit>::insert(const polygon_45_set_data<coord_type>& polygon_set, bool is_hole) { + std::size_t count = data_.size(); + for(typename polygon_45_set_data<coord_type>::iterator_type itr = polygon_set.begin(); + itr != polygon_set.end(); ++itr) { + const typename polygon_45_set_data<coord_type>::Vertex45Compact& v = *itr; + typename polygon_45_set_data<Unit>::Vertex45Compact v2; + v2.pt.x(static_cast<Unit>(v.pt.x())); + v2.pt.y(static_cast<Unit>(v.pt.y())); + v2.count = typename polygon_45_formation<Unit>::Vertex45Count(v.count[0], v.count[1], v.count[2], v.count[3]); + data_.push_back(v2); + } + polygon_45_set_data<coord_type> tmp; + polygon_set.get_error_data(tmp); + for(typename polygon_45_set_data<coord_type>::iterator_type itr = tmp.begin(); + itr != tmp.end(); ++itr) { + const typename polygon_45_set_data<coord_type>::Vertex45Compact& v = *itr; + typename polygon_45_set_data<Unit>::Vertex45Compact v2; + v2.pt.x(static_cast<Unit>(v.pt.x())); + v2.pt.y(static_cast<Unit>(v.pt.y())); + v2.count = typename polygon_45_formation<Unit>::Vertex45Count(v.count[0], v.count[1], v.count[2], v.count[3]); + error_data_.push_back(v2); + } + if(is_hole) { + for(std::size_t i = count; i < data_.size(); ++i) { + data_[i].count = data_[i].count.invert(); + } + } + dirty_ = true; + unsorted_ = true; + if(polygon_set.is_manhattan() == false) is_manhattan_ = false; + return; + } + + template <typename cT, typename rT> + void insert_rectangle_into_vector_45(cT& output, const rT& rect, bool is_hole) { + point_data<typename rectangle_traits<rT>::coordinate_type> + llpt = ll(rect), lrpt = lr(rect), ulpt = ul(rect), urpt = ur(rect); + direction_1d dir = COUNTERCLOCKWISE; + if(is_hole) dir = CLOCKWISE; + insert_vertex_half_edge_45_pair_into_vector(output, llpt, lrpt, urpt, dir); + insert_vertex_half_edge_45_pair_into_vector(output, lrpt, urpt, ulpt, dir); + insert_vertex_half_edge_45_pair_into_vector(output, urpt, ulpt, llpt, dir); + insert_vertex_half_edge_45_pair_into_vector(output, ulpt, llpt, lrpt, dir); + } + + template <typename Unit> + template <typename geometry_type> + inline void polygon_45_set_data<Unit>::insert_dispatch(const geometry_type& geometry_object, + bool is_hole, rectangle_concept ) { + dirty_ = true; + unsorted_ = true; + insert_rectangle_into_vector_45(data_, geometry_object, is_hole); + } + + // get the external boundary rectangle + template <typename Unit> + template <typename rectangle_type> + inline bool polygon_45_set_data<Unit>::extents(rectangle_type& rect) const{ + clean(); + if(empty()) { + return false; + } + Unit low = (std::numeric_limits<Unit>::max)(); + Unit high = (std::numeric_limits<Unit>::min)(); + interval_data<Unit> xivl(low, high); + interval_data<Unit> yivl(low, high); + for(typename value_type::const_iterator itr = data_.begin(); + itr != data_.end(); ++ itr) { + if((*itr).pt.x() > xivl.get(HIGH)) + xivl.set(HIGH, (*itr).pt.x()); + if((*itr).pt.x() < xivl.get(LOW)) + xivl.set(LOW, (*itr).pt.x()); + if((*itr).pt.y() > yivl.get(HIGH)) + yivl.set(HIGH, (*itr).pt.y()); + if((*itr).pt.y() < yivl.get(LOW)) + yivl.set(LOW, (*itr).pt.y()); + } + rect = construct<rectangle_type>(xivl, yivl); + return true; + } + + //this function snaps the vertex and two half edges + //to be both even or both odd coordinate values if one of the edges is 45 + //and throws an excpetion if an edge is non-manhattan, non-45. + template <typename Unit> + inline void polygon_45_set_data<Unit>::snap_vertex_45(typename polygon_45_set_data<Unit>::Vertex45Compact& vertex) { + bool plus45 = vertex.count[2] != 0; + bool minus45 = vertex.count[0] != 0; + if(plus45 || minus45) { + if(abs(vertex.pt.x()) % 2 != abs(vertex.pt.y()) % 2) { + if(vertex.count[1] != 0 || + (plus45 && minus45)) { + //move right + vertex.pt.x(vertex.pt.x() + 1); + } else { + //assert that vertex.count[3] != 0 + Unit modifier = plus45 ? -1 : 1; + vertex.pt.y(vertex.pt.y() + modifier); + } + } + } + } + + template <typename Unit> + inline void polygon_45_set_data<Unit>::snap() const { + for(typename value_type::iterator itr = data_.begin(); + itr != data_.end(); ++itr) { + snap_vertex_45(*itr); + } + } + + // |= &= += *= -= ^= binary operators + template <typename Unit> + inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator|=(const polygon_45_set_data<Unit>& b) { + insert(b); + return *this; + } + template <typename Unit> + inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator&=(const polygon_45_set_data<Unit>& b) { + //b.sort(); + //sort(); + applyAdaptiveBoolean_<1>(b); + dirty_ = false; + unsorted_ = false; + return *this; + } + template <typename Unit> + inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator+=(const polygon_45_set_data<Unit>& b) { + return (*this) |= b; + } + template <typename Unit> + inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator*=(const polygon_45_set_data<Unit>& b) { + return (*this) &= b; + } + template <typename Unit> + inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator-=(const polygon_45_set_data<Unit>& b) { + //b.sort(); + //sort(); + applyAdaptiveBoolean_<2>(b); + dirty_ = false; + unsorted_ = false; + return *this; + } + template <typename Unit> + inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator^=(const polygon_45_set_data<Unit>& b) { + //b.sort(); + //sort(); + applyAdaptiveBoolean_<3>(b); + dirty_ = false; + unsorted_ = false; + return *this; + } + + template <typename Unit> + inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator+=(Unit delta) { + return resize(delta); + } + template <typename Unit> + inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator-=(Unit delta) { + return (*this) += -delta; + } + + template <typename Unit> + inline polygon_45_set_data<Unit>& + polygon_45_set_data<Unit>::resize(Unit resizing, RoundingOption rounding, CornerOption corner) { + if(resizing == 0) return *this; + std::list<polygon_45_with_holes_data<Unit> > pl; + get_polygons_with_holes(pl); + clear(); + for(typename std::list<polygon_45_with_holes_data<Unit> >::iterator itr = pl.begin(); itr != pl.end(); ++itr) { + insert_with_resize(*itr, resizing, rounding, corner); + } + clean(); + //perterb 45 edges to prevent non-integer intersection errors upon boolean op + //snap(); + return *this; + } + + //distance is assumed to be positive + inline int roundClosest(double distance) { + int f = (int)distance; + if(distance - (double)f < 0.5) return f; + return f+1; + } + + //distance is assumed to be positive + template <typename Unit> + inline Unit roundWithOptions(double distance, RoundingOption rounding) { + if(rounding == CLOSEST) { + return roundClosest(distance); + } else if(rounding == OVERSIZE) { + return (Unit)distance + 1; + } else { //UNDERSIZE + return (Unit)distance; + } + } + + // 0 is east, 1 is northeast, 2 is north, 3 is northwest, 4 is west, 5 is southwest, 6 is south + // 7 is southwest + template <typename Unit> + inline point_data<Unit> bloatVertexInDirWithOptions(const point_data<Unit>& point, unsigned int dir, + Unit bloating, RoundingOption rounding) { + const double sqrt2 = 1.4142135623730950488016887242097; + if(dir & 1) { + Unit unitDistance = (Unit)bloating; + if(rounding != SQRT2) { + //45 degree bloating + double distance = (double)bloating; + distance /= sqrt2; // multiply by 1/sqrt2 + unitDistance = roundWithOptions<Unit>(distance, rounding); + } + int xMultiplier = 1; + int yMultiplier = 1; + if(dir == 3 || dir == 5) xMultiplier = -1; + if(dir == 5 || dir == 7) yMultiplier = -1; + return point_data<Unit>(point.x()+xMultiplier*unitDistance, + point.y()+yMultiplier*unitDistance); + } else { + if(dir == 0) + return point_data<Unit>(point.x()+bloating, point.y()); + if(dir == 2) + return point_data<Unit>(point.x(), point.y()+bloating); + if(dir == 4) + return point_data<Unit>(point.x()-bloating, point.y()); + if(dir == 6) + return point_data<Unit>(point.x(), point.y()-bloating); + return point_data<Unit>(); + } + } + + template <typename Unit> + inline unsigned int getEdge45Direction(const point_data<Unit>& pt1, const point_data<Unit>& pt2) { + if(pt1.x() == pt2.x()) { + if(pt1.y() < pt2.y()) return 2; + return 6; + } + if(pt1.y() == pt2.y()) { + if(pt1.x() < pt2.x()) return 0; + return 4; + } + if(pt2.y() > pt1.y()) { + if(pt2.x() > pt1.x()) return 1; + return 3; + } + if(pt2.x() > pt1.x()) return 7; + return 5; + } + + inline unsigned int getEdge45NormalDirection(unsigned int dir, int multiplier) { + if(multiplier < 0) + return (dir + 2) % 8; + return (dir + 4 + 2) % 8; + } + + template <typename Unit> + inline point_data<Unit> getIntersectionPoint(const point_data<Unit>& pt1, unsigned int slope1, + const point_data<Unit>& pt2, unsigned int slope2) { + //the intention here is to use all integer arithmetic without causing overflow + //turncation error or divide by zero error + //I don't use floating point arithmetic because its precision may not be high enough + //at the extremes of the integer range + typedef typename coordinate_traits<Unit>::area_type LongUnit; + const Unit rises[8] = {0, 1, 1, 1, 0, -1, -1, -1}; + const Unit runs[8] = {1, 1, 0, -1, -1, -1, 0, 1}; + LongUnit rise1 = rises[slope1]; + LongUnit rise2 = rises[slope2]; + LongUnit run1 = runs[slope1]; + LongUnit run2 = runs[slope2]; + LongUnit x1 = (LongUnit)pt1.x(); + LongUnit x2 = (LongUnit)pt2.x(); + LongUnit y1 = (LongUnit)pt1.y(); + LongUnit y2 = (LongUnit)pt2.y(); + Unit x = 0; + Unit y = 0; + if(run1 == 0) { + x = pt1.x(); + y = (Unit)(((x1 - x2) * rise2) / run2) + pt2.y(); + } else if(run2 == 0) { + x = pt2.x(); + y = (Unit)(((x2 - x1) * rise1) / run1) + pt1.y(); + } else { + // y - y1 = (rise1/run1)(x - x1) + // y - y2 = (rise2/run2)(x - x2) + // y = (rise1/run1)(x - x1) + y1 = (rise2/run2)(x - x2) + y2 + // (rise1/run1 - rise2/run2)x = y2 - y1 + rise1/run1 x1 - rise2/run2 x2 + // x = (y2 - y1 + rise1/run1 x1 - rise2/run2 x2)/(rise1/run1 - rise2/run2) + // x = (y2 - y1 + rise1/run1 x1 - rise2/run2 x2)(rise1 run2 - rise2 run1)/(run1 run2) + x = (Unit)((y2 - y1 + ((rise1 * x1) / run1) - ((rise2 * x2) / run2)) * + (run1 * run2) / (rise1 * run2 - rise2 * run1)); + if(rise1 == 0) { + y = pt1.y(); + } else if(rise2 == 0) { + y = pt2.y(); + } else { + // y - y1 = (rise1/run1)(x - x1) + // (run1/rise1)(y - y1) = x - x1 + // x = (run1/rise1)(y - y1) + x1 = (run2/rise2)(y - y2) + x2 + y = (Unit)((x2 - x1 + ((run1 * y1) / rise1) - ((run2 * y2) / rise2)) * + (rise1 * rise2) / (run1 * rise2 - run2 * rise1)); + } + } + return point_data<Unit>(x, y); + } + + template <typename Unit> + inline + void handleResizingEdge45_SQRT1OVER2(polygon_45_set_data<Unit>& sizingSet, point_data<Unit> first, + point_data<Unit> second, Unit resizing, CornerOption corner) { + if(first.x() == second.x()) { + sizingSet.insert(rectangle_data<Unit>(first.x() - resizing, first.y(), first.x() + resizing, second.y())); + return; + } + if(first.y() == second.y()) { + sizingSet.insert(rectangle_data<Unit>(first.x(), first.y() - resizing, second.x(), first.y() + resizing)); + return; + } + std::vector<point_data<Unit> > pts; + Unit bloating = resizing < 0 ? -resizing : resizing; + if(corner == UNFILLED) { + //we have to round up + bloating = bloating / 2 + bloating % 2 ; //round up + if(second.x() < first.x()) std::swap(first, second); + if(first.y() < second.y()) { //upward sloping + pts.push_back(point_data<Unit>(first.x() + bloating, first.y() - bloating)); + pts.push_back(point_data<Unit>(first.x() - bloating, first.y() + bloating)); + pts.push_back(point_data<Unit>(second.x() - bloating, second.y() + bloating)); + pts.push_back(point_data<Unit>(second.x() + bloating, second.y() - bloating)); + sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), CLOCKWISE, false); + } else { //downward sloping + pts.push_back(point_data<Unit>(first.x() + bloating, first.y() + bloating)); + pts.push_back(point_data<Unit>(first.x() - bloating, first.y() - bloating)); + pts.push_back(point_data<Unit>(second.x() - bloating, second.y() - bloating)); + pts.push_back(point_data<Unit>(second.x() + bloating, second.y() + bloating)); + sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), COUNTERCLOCKWISE, false); + } + return; + } + if(second.x() < first.x()) std::swap(first, second); + if(first.y() < second.y()) { //upward sloping + pts.push_back(point_data<Unit>(first.x(), first.y() - bloating)); + pts.push_back(point_data<Unit>(first.x() - bloating, first.y())); + pts.push_back(point_data<Unit>(second.x(), second.y() + bloating)); + pts.push_back(point_data<Unit>(second.x() + bloating, second.y())); + sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), CLOCKWISE, false); + } else { //downward sloping + pts.push_back(point_data<Unit>(first.x() - bloating, first.y())); + pts.push_back(point_data<Unit>(first.x(), first.y() + bloating)); + pts.push_back(point_data<Unit>(second.x() + bloating, second.y())); + pts.push_back(point_data<Unit>(second.x(), second.y() - bloating)); + sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), CLOCKWISE, false); + } + } + + + template <typename Unit> + inline + void handleResizingEdge45(polygon_45_set_data<Unit>& sizingSet, point_data<Unit> first, + point_data<Unit> second, Unit resizing, RoundingOption rounding) { + if(first.x() == second.x()) { + sizingSet.insert(rectangle_data<int>(first.x() - resizing, first.y(), first.x() + resizing, second.y())); + return; + } + if(first.y() == second.y()) { + sizingSet.insert(rectangle_data<int>(first.x(), first.y() - resizing, second.x(), first.y() + resizing)); + return; + } + //edge is 45 + std::vector<point_data<Unit> > pts; + Unit bloating = resizing < 0 ? -resizing : resizing; + if(second.x() < first.x()) std::swap(first, second); + if(first.y() < second.y()) { + pts.push_back(bloatVertexInDirWithOptions(first, 3, bloating, rounding)); + pts.push_back(bloatVertexInDirWithOptions(first, 7, bloating, rounding)); + pts.push_back(bloatVertexInDirWithOptions(second, 7, bloating, rounding)); + pts.push_back(bloatVertexInDirWithOptions(second, 3, bloating, rounding)); + sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), HIGH, false); + } else { + pts.push_back(bloatVertexInDirWithOptions(first, 1, bloating, rounding)); + pts.push_back(bloatVertexInDirWithOptions(first, 5, bloating, rounding)); + pts.push_back(bloatVertexInDirWithOptions(second, 5, bloating, rounding)); + pts.push_back(bloatVertexInDirWithOptions(second, 1, bloating, rounding)); + sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), HIGH, false); + } + } + + template <typename Unit> + inline point_data<Unit> bloatVertexInDirWithSQRT1OVER2(int edge1, int normal1, const point_data<Unit>& second, Unit bloating, + bool first) { + orientation_2d orient = first ? HORIZONTAL : VERTICAL; + orientation_2d orientp = orient.get_perpendicular(); + int multiplier = first ? 1 : -1; + point_data<Unit> pt1(second); + if(edge1 == 1) { + if(normal1 == 3) { + move(pt1, orient, -multiplier * bloating); + } else { + move(pt1, orientp, -multiplier * bloating); + } + } else if(edge1 == 3) { + if(normal1 == 1) { + move(pt1, orient, multiplier * bloating); + } else { + move(pt1, orientp, -multiplier * bloating); + } + } else if(edge1 == 5) { + if(normal1 == 3) { + move(pt1, orientp, multiplier * bloating); + } else { + move(pt1, orient, multiplier * bloating); + } + } else { + if(normal1 == 5) { + move(pt1, orient, -multiplier * bloating); + } else { + move(pt1, orientp, multiplier * bloating); + } + } + return pt1; + } + + template <typename Unit> + inline + void handleResizingVertex45(polygon_45_set_data<Unit>& sizingSet, const point_data<Unit>& first, + const point_data<Unit>& second, const point_data<Unit>& third, Unit resizing, + RoundingOption rounding, CornerOption corner, + int multiplier) { + unsigned int edge1 = getEdge45Direction(first, second); + unsigned int edge2 = getEdge45Direction(second, third); + unsigned int diffAngle; + if(multiplier < 0) + diffAngle = (edge2 + 8 - edge1) % 8; + else + diffAngle = (edge1 + 8 - edge2) % 8; + if(diffAngle < 4) { + if(resizing > 0) return; //accute interior corner + else multiplier *= -1; //make it appear to be an accute exterior angle + } + Unit bloating = abs(resizing); + if(rounding == SQRT1OVER2) { + if(edge1 % 2 && edge2 % 2) return; + if(corner == ORTHOGONAL && edge1 % 2 == 0 && edge2 % 2 == 0) { + rectangle_data<Unit> insertion_rect; + set_points(insertion_rect, second, second); + bloat(insertion_rect, bloating); + sizingSet.insert(insertion_rect); + } else if(corner != ORTHOGONAL) { + point_data<Unit> pt1(0, 0); + point_data<Unit> pt2(0, 0); + unsigned int normal1 = getEdge45NormalDirection(edge1, multiplier); + unsigned int normal2 = getEdge45NormalDirection(edge2, multiplier); + if(edge1 % 2) { + pt1 = bloatVertexInDirWithSQRT1OVER2(edge1, normal1, second, bloating, true); + } else { + pt1 = bloatVertexInDirWithOptions(second, normal1, bloating, UNDERSIZE); + } + if(edge2 % 2) { + pt2 = bloatVertexInDirWithSQRT1OVER2(edge2, normal2, second, bloating, false); + } else { + pt2 = bloatVertexInDirWithOptions(second, normal2, bloating, UNDERSIZE); + } + std::vector<point_data<Unit> > pts; + pts.push_back(pt1); + pts.push_back(second); + pts.push_back(pt2); + pts.push_back(getIntersectionPoint(pt1, edge1, pt2, edge2)); + polygon_45_data<Unit> poly(pts.begin(), pts.end()); + sizingSet.insert(poly); + } else { + //ORTHOGONAL of a 45 degree corner + int normal = 0; + if(edge1 % 2) { + normal = getEdge45NormalDirection(edge2, multiplier); + } else { + normal = getEdge45NormalDirection(edge1, multiplier); + } + rectangle_data<Unit> insertion_rect; + point_data<Unit> edgePoint = bloatVertexInDirWithOptions(second, normal, bloating, UNDERSIZE); + set_points(insertion_rect, second, edgePoint); + if(normal == 0 || normal == 4) + bloat(insertion_rect, VERTICAL, bloating); + else + bloat(insertion_rect, HORIZONTAL, bloating); + sizingSet.insert(insertion_rect); + } + return; + } + unsigned int normal1 = getEdge45NormalDirection(edge1, multiplier); + unsigned int normal2 = getEdge45NormalDirection(edge2, multiplier); + point_data<Unit> edgePoint1 = bloatVertexInDirWithOptions(second, normal1, bloating, rounding); + point_data<Unit> edgePoint2 = bloatVertexInDirWithOptions(second, normal2, bloating, rounding); + //if the change in angle is 135 degrees it is an accute exterior corner + if((edge1+ multiplier * 3) % 8 == edge2) { + if(corner == ORTHOGONAL) { + rectangle_data<Unit> insertion_rect; + set_points(insertion_rect, edgePoint1, edgePoint2); + sizingSet.insert(insertion_rect); + return; + } + } + std::vector<point_data<Unit> > pts; + pts.push_back(edgePoint1); + pts.push_back(second); + pts.push_back(edgePoint2); + pts.push_back(getIntersectionPoint(edgePoint1, edge1, edgePoint2, edge2)); + polygon_45_data<Unit> poly(pts.begin(), pts.end()); + sizingSet.insert(poly); + } + + template <typename Unit> + template <typename geometry_type> + inline polygon_45_set_data<Unit>& + polygon_45_set_data<Unit>::insert_with_resize_dispatch(const geometry_type& poly, + coordinate_type resizing, + RoundingOption rounding, + CornerOption corner, + bool hole, polygon_45_concept ) { + direction_1d wdir = winding(poly); + int multiplier = wdir == LOW ? -1 : 1; + if(hole) resizing *= -1; + typedef typename polygon_45_data<Unit>::iterator_type piterator; + piterator first, second, third, end, real_end; + real_end = end_points(poly); + third = begin_points(poly); + first = third; + if(first == real_end) return *this; + ++third; + if(third == real_end) return *this; + second = end = third; + ++third; + if(third == real_end) return *this; + polygon_45_set_data<Unit> sizingSet; + //insert minkofski shapes on edges and corners + do { + if(rounding != SQRT1OVER2) { + handleResizingEdge45(sizingSet, *first, *second, resizing, rounding); + } else { + handleResizingEdge45_SQRT1OVER2(sizingSet, *first, *second, resizing, corner); + } + if(corner != UNFILLED) + handleResizingVertex45(sizingSet, *first, *second, *third, resizing, rounding, corner, multiplier); + first = second; + second = third; + ++third; + if(third == real_end) { + third = begin_points(poly); + if(*second == *third) { + ++third; //skip first point if it is duplicate of last point + } + } + } while(second != end); + //sizingSet.snap(); + polygon_45_set_data<Unit> tmp; + //insert original shape + tmp.insert_dispatch(poly, false, polygon_45_concept()); + if(resizing < 0) tmp -= sizingSet; + else tmp += sizingSet; + tmp.clean(); + insert(tmp, hole); + dirty_ = true; + unsorted_ = true; + return (*this); + } + + // accumulate the bloated polygon with holes + template <typename Unit> + template <typename geometry_type> + inline polygon_45_set_data<Unit>& + polygon_45_set_data<Unit>::insert_with_resize_dispatch(const geometry_type& poly, + coordinate_type resizing, + RoundingOption rounding, + CornerOption corner, + bool hole, polygon_45_with_holes_concept ) { + insert_with_resize_dispatch(poly, resizing, rounding, corner, hole, polygon_45_concept()); + for(typename polygon_with_holes_traits<geometry_type>::iterator_holes_type itr = + begin_holes(poly); itr != end_holes(poly); + ++itr) { + insert_with_resize_dispatch(*itr, resizing, rounding, corner, !hole, polygon_45_concept()); + } + return *this; + } + + // transform set + template <typename Unit> + template <typename transformation_type> + inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::transform(const transformation_type& tr){ + clean(); + std::vector<polygon_45_with_holes_data<Unit> > polys; + get(polys); + for(typename std::vector<polygon_45_with_holes_data<Unit> >::iterator itr = polys.begin(); + itr != polys.end(); ++itr) { + ::boost::polygon::transform(*itr, tr); + } + clear(); + insert(polys.begin(), polys.end()); + dirty_ = true; + unsorted_ = true; + return *this; + } + + template <typename Unit> + inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::scale_up(typename coordinate_traits<Unit>::unsigned_area_type factor) { + scale_up_vertex_45_compact_range(data_.begin(), data_.end(), factor); + return *this; + } + + template <typename Unit> + inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::scale_down(typename coordinate_traits<Unit>::unsigned_area_type factor) { + clean(); + std::vector<polygon_45_with_holes_data<Unit> > polys; + get_polygons_with_holes(polys); + for(typename std::vector<polygon_45_with_holes_data<Unit> >::iterator itr = polys.begin(); + itr != polys.end(); ++itr) { + ::boost::polygon::scale_down(*itr, factor); + } + clear(); + insert(polys.begin(), polys.end()); + dirty_ = true; + unsorted_ = true; + return *this; + } + + template <typename Unit> + inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::scale(double factor) { + clean(); + std::vector<polygon_45_with_holes_data<Unit> > polys; + get_polygons_with_holes(polys); + for(typename std::vector<polygon_45_with_holes_data<Unit> >::iterator itr = polys.begin(); + itr != polys.end(); ++itr) { + ::boost::polygon::scale(*itr, factor); + } + clear(); + insert(polys.begin(), polys.end()); + dirty_ = true; + unsorted_ = true; + return *this; + } + + template <typename Unit> + inline bool polygon_45_set_data<Unit>::clean() const { + if(unsorted_) sort(); + if(dirty_) { + applyAdaptiveUnary_<0>(); + dirty_ = false; + } + return true; + } + + template <typename Unit> + template <int op> + inline void polygon_45_set_data<Unit>::applyAdaptiveBoolean_(const polygon_45_set_data<Unit>& rvalue) const { + polygon_45_set_data<Unit> tmp; + applyAdaptiveBoolean_<op>(tmp, rvalue); + data_.swap(tmp.data_); //swapping vectors should be constant time operation + error_data_.swap(tmp.error_data_); + is_manhattan_ = tmp.is_manhattan_; + unsorted_ = false; + dirty_ = false; + } + + template <typename Unit2, int op> + bool applyBoolean45OpOnVectors(std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact>& result_data, + std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact>& lvalue_data, + std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact>& rvalue_data + ) { + bool result_is_manhattan_ = true; + typename boolean_op_45<Unit2>::template Scan45<typename boolean_op_45<Unit2>::Count2, + typename boolean_op_45<Unit2>::template boolean_op_45_output_functor<op> > scan45; + std::vector<typename boolean_op_45<Unit2>::Vertex45> eventOut; + typedef std::pair<typename boolean_op_45<Unit2>::Point, + typename boolean_op_45<Unit2>::template Scan45CountT<typename boolean_op_45<Unit2>::Count2> > Scan45Vertex; + std::vector<Scan45Vertex> eventIn; + typedef std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact> value_type; + typename value_type::const_iterator iter1 = lvalue_data.begin(); + typename value_type::const_iterator iter2 = rvalue_data.begin(); + typename value_type::const_iterator end1 = lvalue_data.end(); + typename value_type::const_iterator end2 = rvalue_data.end(); + const Unit2 UnitMax = (std::numeric_limits<Unit2>::max)(); + Unit2 x = UnitMax; + while(iter1 != end1 || iter2 != end2) { + Unit2 currentX = UnitMax; + if(iter1 != end1) currentX = iter1->pt.x(); + if(iter2 != end2) currentX = (std::min)(currentX, iter2->pt.x()); + if(currentX != x) { + //std::cout << "SCAN " << currentX << "\n"; + //scan event + scan45.scan(eventOut, eventIn.begin(), eventIn.end()); + gtlsort(eventOut.begin(), eventOut.end()); + std::size_t ptCount = 0; + for(std::size_t i = 0; i < eventOut.size(); ++i) { + if(!result_data.empty() && + result_data.back().pt == eventOut[i].pt) { + result_data.back().count += eventOut[i]; + ++ptCount; + } else { + if(!result_data.empty()) { + if(result_data.back().count.is_45()) { + result_is_manhattan_ = false; + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + } + result_data.push_back(eventOut[i]); + ptCount = 1; + } + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + eventOut.clear(); + eventIn.clear(); + x = currentX; + } + //std::cout << "get next\n"; + if(iter2 != end2 && (iter1 == end1 || iter2->pt.x() < iter1->pt.x() || + (iter2->pt.x() == iter1->pt.x() && + iter2->pt.y() < iter1->pt.y()) )) { + //std::cout << "case1 next\n"; + eventIn.push_back(Scan45Vertex + (iter2->pt, + typename polygon_45_formation<Unit2>:: + Scan45Count(typename polygon_45_formation<Unit2>::Count2(0, iter2->count[0]), + typename polygon_45_formation<Unit2>::Count2(0, iter2->count[1]), + typename polygon_45_formation<Unit2>::Count2(0, iter2->count[2]), + typename polygon_45_formation<Unit2>::Count2(0, iter2->count[3])))); + ++iter2; + } else if(iter1 != end1 && (iter2 == end2 || iter1->pt.x() < iter2->pt.x() || + (iter1->pt.x() == iter2->pt.x() && + iter1->pt.y() < iter2->pt.y()) )) { + //std::cout << "case2 next\n"; + eventIn.push_back(Scan45Vertex + (iter1->pt, + typename polygon_45_formation<Unit2>:: + Scan45Count( + typename polygon_45_formation<Unit2>::Count2(iter1->count[0], 0), + typename polygon_45_formation<Unit2>::Count2(iter1->count[1], 0), + typename polygon_45_formation<Unit2>::Count2(iter1->count[2], 0), + typename polygon_45_formation<Unit2>::Count2(iter1->count[3], 0)))); + ++iter1; + } else { + //std::cout << "case3 next\n"; + eventIn.push_back(Scan45Vertex + (iter2->pt, + typename polygon_45_formation<Unit2>:: + Scan45Count(typename polygon_45_formation<Unit2>::Count2(iter1->count[0], + iter2->count[0]), + typename polygon_45_formation<Unit2>::Count2(iter1->count[1], + iter2->count[1]), + typename polygon_45_formation<Unit2>::Count2(iter1->count[2], + iter2->count[2]), + typename polygon_45_formation<Unit2>::Count2(iter1->count[3], + iter2->count[3])))); + ++iter1; + ++iter2; + } + } + scan45.scan(eventOut, eventIn.begin(), eventIn.end()); + gtlsort(eventOut.begin(), eventOut.end()); + + std::size_t ptCount = 0; + for(std::size_t i = 0; i < eventOut.size(); ++i) { + if(!result_data.empty() && + result_data.back().pt == eventOut[i].pt) { + result_data.back().count += eventOut[i]; + ++ptCount; + } else { + if(!result_data.empty()) { + if(result_data.back().count.is_45()) { + result_is_manhattan_ = false; + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + } + result_data.push_back(eventOut[i]); + ptCount = 1; + } + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + if(!result_data.empty() && + result_data.back().count.is_45()) { + result_is_manhattan_ = false; + } + return result_is_manhattan_; + } + + template <typename Unit2, int op> + bool applyUnary45OpOnVectors(std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact>& result_data, + std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact>& lvalue_data ) { + bool result_is_manhattan_ = true; + typename boolean_op_45<Unit2>::template Scan45<typename boolean_op_45<Unit2>::Count1, + typename boolean_op_45<Unit2>::template unary_op_45_output_functor<op> > scan45; + std::vector<typename boolean_op_45<Unit2>::Vertex45> eventOut; + typedef typename boolean_op_45<Unit2>::template Scan45CountT<typename boolean_op_45<Unit2>::Count1> Scan45Count; + typedef std::pair<typename boolean_op_45<Unit2>::Point, Scan45Count> Scan45Vertex; + std::vector<Scan45Vertex> eventIn; + typedef std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact> value_type; + typename value_type::const_iterator iter1 = lvalue_data.begin(); + typename value_type::const_iterator end1 = lvalue_data.end(); + const Unit2 UnitMax = (std::numeric_limits<Unit2>::max)(); + Unit2 x = UnitMax; + while(iter1 != end1) { + Unit2 currentX = iter1->pt.x(); + if(currentX != x) { + //std::cout << "SCAN " << currentX << "\n"; + //scan event + scan45.scan(eventOut, eventIn.begin(), eventIn.end()); + gtlsort(eventOut.begin(), eventOut.end()); + std::size_t ptCount = 0; + for(std::size_t i = 0; i < eventOut.size(); ++i) { + if(!result_data.empty() && + result_data.back().pt == eventOut[i].pt) { + result_data.back().count += eventOut[i]; + ++ptCount; + } else { + if(!result_data.empty()) { + if(result_data.back().count.is_45()) { + result_is_manhattan_ = false; + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + } + result_data.push_back(eventOut[i]); + ptCount = 1; + } + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + eventOut.clear(); + eventIn.clear(); + x = currentX; + } + //std::cout << "get next\n"; + eventIn.push_back(Scan45Vertex + (iter1->pt, + Scan45Count( typename boolean_op_45<Unit2>::Count1(iter1->count[0]), + typename boolean_op_45<Unit2>::Count1(iter1->count[1]), + typename boolean_op_45<Unit2>::Count1(iter1->count[2]), + typename boolean_op_45<Unit2>::Count1(iter1->count[3])))); + ++iter1; + } + scan45.scan(eventOut, eventIn.begin(), eventIn.end()); + gtlsort(eventOut.begin(), eventOut.end()); + + std::size_t ptCount = 0; + for(std::size_t i = 0; i < eventOut.size(); ++i) { + if(!result_data.empty() && + result_data.back().pt == eventOut[i].pt) { + result_data.back().count += eventOut[i]; + ++ptCount; + } else { + if(!result_data.empty()) { + if(result_data.back().count.is_45()) { + result_is_manhattan_ = false; + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + } + result_data.push_back(eventOut[i]); + ptCount = 1; + } + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + if(!result_data.empty() && + result_data.back().count.is_45()) { + result_is_manhattan_ = false; + } + return result_is_manhattan_; + } + + template <typename cT, typename iT> + void get_error_rects_shell(cT& posE, cT& negE, iT beginr, iT endr) { + typedef typename iT::value_type Point; + typedef typename point_traits<Point>::coordinate_type Unit; + typedef typename coordinate_traits<Unit>::area_type area_type; + Point pt1, pt2, pt3; + bool i1 = true; + bool i2 = true; + bool not_done = beginr != endr; + bool next_to_last = false; + bool last = false; + Point first, second; + while(not_done) { + if(last) { + last = false; + not_done = false; + pt3 = second; + } else if(next_to_last) { + next_to_last = false; + last = true; + pt3 = first; + } else if(i1) { + const Point& pt = *beginr; + first = pt1 = pt; + i1 = false; + i2 = true; + ++beginr; + if(beginr == endr) return; //too few points + continue; + } else if (i2) { + const Point& pt = *beginr; + second = pt2 = pt; + i2 = false; + ++beginr; + if(beginr == endr) return; //too few points + continue; + } else { + const Point& pt = *beginr; + pt3 = pt; + ++beginr; + if(beginr == endr) { + next_to_last = true; + //skip last point equal to first + continue; + } + } + if(local_abs(x(pt2)) % 2) { //y % 2 should also be odd + //is corner concave or convex? + Point pts[] = {pt1, pt2, pt3}; + area_type ar = point_sequence_area<Point*, area_type>(pts, pts+3); + direction_1d dir = ar < 0 ? COUNTERCLOCKWISE : CLOCKWISE; + //std::cout << pt1 << " " << pt2 << " " << pt3 << " " << ar << std::endl; + if(dir == CLOCKWISE) { + posE.push_back(rectangle_data<typename Point::coordinate_type> + (x(pt2) - 1, y(pt2) - 1, x(pt2) + 1, y(pt2) + 1)); + + } else { + negE.push_back(rectangle_data<typename Point::coordinate_type> + (x(pt2) - 1, y(pt2) - 1, x(pt2) + 1, y(pt2) + 1)); + } + } + pt1 = pt2; + pt2 = pt3; + } + } + + template <typename cT, typename pT> + void get_error_rects(cT& posE, cT& negE, const pT& p) { + get_error_rects_shell(posE, negE, p.begin(), p.end()); + for(typename pT::iterator_holes_type iHb = p.begin_holes(); + iHb != p.end_holes(); ++iHb) { + get_error_rects_shell(posE, negE, iHb->begin(), iHb->end()); + } + } + + template <typename Unit> + template <int op> + inline void polygon_45_set_data<Unit>::applyAdaptiveBoolean_(polygon_45_set_data<Unit>& result, + const polygon_45_set_data<Unit>& rvalue) const { + result.clear(); + result.error_data_ = error_data_; + result.error_data_.insert(result.error_data_.end(), rvalue.error_data_.begin(), + rvalue.error_data_.end()); + if(is_manhattan() && rvalue.is_manhattan()) { + //convert each into polygon_90_set data and call boolean operations + polygon_90_set_data<Unit> l90sd(VERTICAL), r90sd(VERTICAL), output(VERTICAL); + for(typename value_type::const_iterator itr = data_.begin(); itr != data_.end(); ++itr) { + if((*itr).count[3] == 0) continue; //skip all non vertical edges + l90sd.insert(std::make_pair((*itr).pt.x(), std::make_pair<Unit, int>((*itr).pt.y(), (*itr).count[3])), false, VERTICAL); + } + for(typename value_type::const_iterator itr = rvalue.data_.begin(); itr != rvalue.data_.end(); ++itr) { + if((*itr).count[3] == 0) continue; //skip all non vertical edges + r90sd.insert(std::make_pair((*itr).pt.x(), std::make_pair<Unit, int>((*itr).pt.y(), (*itr).count[3])), false, VERTICAL); + } + l90sd.sort(); + r90sd.sort(); +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op == 0) { + output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), + r90sd.begin(), r90sd.end(), boolean_op::BinaryCount<boolean_op::BinaryOr>()); + } else if (op == 1) { + output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), + r90sd.begin(), r90sd.end(), boolean_op::BinaryCount<boolean_op::BinaryAnd>()); + } else if (op == 2) { + output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), + r90sd.begin(), r90sd.end(), boolean_op::BinaryCount<boolean_op::BinaryNot>()); + } else if (op == 3) { + output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), + r90sd.begin(), r90sd.end(), boolean_op::BinaryCount<boolean_op::BinaryXor>()); + } +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + result.data_.clear(); + result.insert(output); + result.is_manhattan_ = true; + result.dirty_ = false; + result.unsorted_ = false; + } else { + sort(); + rvalue.sort(); + try { + result.is_manhattan_ = applyBoolean45OpOnVectors<Unit, op>(result.data_, data_, rvalue.data_); + } catch (std::string str) { + std::string msg = "GTL 45 Boolean error, precision insufficient to represent edge intersection coordinate value."; + if(str == msg) { + result.clear(); + typedef typename coordinate_traits<Unit>::manhattan_area_type Unit2; + typedef typename polygon_45_formation<Unit2>::Vertex45Compact Vertex45Compact2; + typedef std::vector<Vertex45Compact2> Data2; + Data2 rvalue_data, lvalue_data, result_data; + rvalue_data.reserve(rvalue.data_.size()); + lvalue_data.reserve(data_.size()); + for(std::size_t i = 0 ; i < data_.size(); ++i) { + const Vertex45Compact& vi = data_[i]; + Vertex45Compact2 ci; + ci.pt = point_data<Unit2>(x(vi.pt), y(vi.pt)); + ci.count = typename polygon_45_formation<Unit2>::Vertex45Count + ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); + lvalue_data.push_back(ci); + } + for(std::size_t i = 0 ; i < rvalue.data_.size(); ++i) { + const Vertex45Compact& vi = rvalue.data_[i]; + Vertex45Compact2 ci; + ci.pt = (point_data<Unit2>(x(vi.pt), y(vi.pt))); + ci.count = typename polygon_45_formation<Unit2>::Vertex45Count + ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); + rvalue_data.push_back(ci); + } + scale_up_vertex_45_compact_range(lvalue_data.begin(), lvalue_data.end(), 2); + scale_up_vertex_45_compact_range(rvalue_data.begin(), rvalue_data.end(), 2); + bool result_is_manhattan = applyBoolean45OpOnVectors<Unit2, op>(result_data, + lvalue_data, + rvalue_data ); + if(!result_is_manhattan) { + typename polygon_45_formation<Unit2>::Polygon45Formation pf(false); + //std::cout << "FORMING POLYGONS\n"; + std::vector<polygon_45_with_holes_data<Unit2> > container; + pf.scan(container, result_data.begin(), result_data.end()); + Data2 error_data_out; + std::vector<rectangle_data<Unit2> > pos_error_rects; + std::vector<rectangle_data<Unit2> > neg_error_rects; + for(std::size_t i = 0; i < container.size(); ++i) { + get_error_rects(pos_error_rects, neg_error_rects, container[i]); + } + for(std::size_t i = 0; i < pos_error_rects.size(); ++i) { + insert_rectangle_into_vector_45(result_data, pos_error_rects[i], false); + insert_rectangle_into_vector_45(error_data_out, pos_error_rects[i], false); + } + for(std::size_t i = 0; i < neg_error_rects.size(); ++i) { + insert_rectangle_into_vector_45(result_data, neg_error_rects[i], true); + insert_rectangle_into_vector_45(error_data_out, neg_error_rects[i], false); + } + scale_down_vertex_45_compact_range_blindly(error_data_out.begin(), error_data_out.end(), 2); + for(std::size_t i = 0 ; i < error_data_out.size(); ++i) { + const Vertex45Compact2& vi = error_data_out[i]; + Vertex45Compact ci; + ci.pt.x(static_cast<Unit>(x(vi.pt))); + ci.pt.y(static_cast<Unit>(y(vi.pt))); + ci.count = typename polygon_45_formation<Unit>::Vertex45Count + ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); + result.error_data_.push_back(ci); + } + Data2 new_result_data; + gtlsort(result_data.begin(), result_data.end()); + applyUnary45OpOnVectors<Unit2, 0>(new_result_data, result_data); //OR operation + result_data.swap(new_result_data); + } + scale_down_vertex_45_compact_range_blindly(result_data.begin(), result_data.end(), 2); + //result.data_.reserve(result_data.size()); + for(std::size_t i = 0 ; i < result_data.size(); ++i) { + const Vertex45Compact2& vi = result_data[i]; + Vertex45Compact ci; + ci.pt.x(static_cast<Unit>(x(vi.pt))); + ci.pt.y(static_cast<Unit>(y(vi.pt))); + ci.count = typename polygon_45_formation<Unit>::Vertex45Count + ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); + result.data_.push_back(ci); + } + result.is_manhattan_ = result_is_manhattan; + result.dirty_ = false; + result.unsorted_ = false; + } else { throw str; } + } + //std::cout << "DONE SCANNING\n"; + } + } + + template <typename Unit> + template <int op> + inline void polygon_45_set_data<Unit>::applyAdaptiveUnary_() const { + polygon_45_set_data<Unit> result; + result.error_data_ = error_data_; + if(is_manhattan()) { + //convert each into polygon_90_set data and call boolean operations + polygon_90_set_data<Unit> l90sd(VERTICAL); + for(typename value_type::const_iterator itr = data_.begin(); itr != data_.end(); ++itr) { + if((*itr).count[3] == 0) continue; //skip all non vertical edges + l90sd.insert(std::make_pair((*itr).pt.x(), std::make_pair<Unit, int>((*itr).pt.y(), (*itr).count[3])), false, VERTICAL); + } + l90sd.sort(); +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op == 0) { + l90sd.clean(); + } else if (op == 1) { + l90sd.self_intersect(); + } else if (op == 3) { + l90sd.self_xor(); + } +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + result.data_.clear(); + result.insert(l90sd); + result.is_manhattan_ = true; + result.dirty_ = false; + result.unsorted_ = false; + } else { + sort(); + try { + result.is_manhattan_ = applyUnary45OpOnVectors<Unit, op>(result.data_, data_); + } catch (std::string str) { + std::string msg = "GTL 45 Boolean error, precision insufficient to represent edge intersection coordinate value."; + if(str == msg) { + result.clear(); + typedef typename coordinate_traits<Unit>::manhattan_area_type Unit2; + typedef typename polygon_45_formation<Unit2>::Vertex45Compact Vertex45Compact2; + typedef std::vector<Vertex45Compact2> Data2; + Data2 lvalue_data, result_data; + lvalue_data.reserve(data_.size()); + for(std::size_t i = 0 ; i < data_.size(); ++i) { + const Vertex45Compact& vi = data_[i]; + Vertex45Compact2 ci; + ci.pt.x(static_cast<Unit>(x(vi.pt))); + ci.pt.y(static_cast<Unit>(y(vi.pt))); + ci.count = typename polygon_45_formation<Unit2>::Vertex45Count + ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); + lvalue_data.push_back(ci); + } + scale_up_vertex_45_compact_range(lvalue_data.begin(), lvalue_data.end(), 2); + bool result_is_manhattan = applyUnary45OpOnVectors<Unit2, op>(result_data, + lvalue_data ); + if(!result_is_manhattan) { + typename polygon_45_formation<Unit2>::Polygon45Formation pf(false); + //std::cout << "FORMING POLYGONS\n"; + std::vector<polygon_45_with_holes_data<Unit2> > container; + pf.scan(container, result_data.begin(), result_data.end()); + Data2 error_data_out; + std::vector<rectangle_data<Unit2> > pos_error_rects; + std::vector<rectangle_data<Unit2> > neg_error_rects; + for(std::size_t i = 0; i < container.size(); ++i) { + get_error_rects(pos_error_rects, neg_error_rects, container[i]); + } + for(std::size_t i = 0; i < pos_error_rects.size(); ++i) { + insert_rectangle_into_vector_45(result_data, pos_error_rects[i], false); + insert_rectangle_into_vector_45(error_data_out, pos_error_rects[i], false); + } + for(std::size_t i = 0; i < neg_error_rects.size(); ++i) { + insert_rectangle_into_vector_45(result_data, neg_error_rects[i], true); + insert_rectangle_into_vector_45(error_data_out, neg_error_rects[i], false); + } + scale_down_vertex_45_compact_range_blindly(error_data_out.begin(), error_data_out.end(), 2); + for(std::size_t i = 0 ; i < error_data_out.size(); ++i) { + const Vertex45Compact2& vi = error_data_out[i]; + Vertex45Compact ci; + ci.pt.x(static_cast<Unit>(x(vi.pt))); + ci.pt.y(static_cast<Unit>(y(vi.pt))); + ci.count = typename polygon_45_formation<Unit>::Vertex45Count + ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); + result.error_data_.push_back(ci); + } + Data2 new_result_data; + gtlsort(result_data.begin(), result_data.end()); + applyUnary45OpOnVectors<Unit2, 0>(new_result_data, result_data); //OR operation + result_data.swap(new_result_data); + } + scale_down_vertex_45_compact_range_blindly(result_data.begin(), result_data.end(), 2); + //result.data_.reserve(result_data.size()); + for(std::size_t i = 0 ; i < result_data.size(); ++i) { + const Vertex45Compact2& vi = result_data[i]; + Vertex45Compact ci; + ci.pt.x(static_cast<Unit>(x(vi.pt))); + ci.pt.y(static_cast<Unit>(y(vi.pt))); + ci.count = typename polygon_45_formation<Unit>::Vertex45Count + ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); + result.data_.push_back(ci); + } + result.is_manhattan_ = result_is_manhattan; + result.dirty_ = false; + result.unsorted_ = false; + } else { throw str; } + } + //std::cout << "DONE SCANNING\n"; + } + data_.swap(result.data_); + error_data_.swap(result.error_data_); + dirty_ = result.dirty_; + unsorted_ = result.unsorted_; + is_manhattan_ = result.is_manhattan_; + } + + template <typename coordinate_type, typename property_type> + class property_merge_45 { + private: + typedef typename coordinate_traits<coordinate_type>::manhattan_area_type big_coord; + typedef typename polygon_45_property_merge<big_coord, property_type>::MergeSetData tsd; + tsd tsd_; + public: + inline property_merge_45() : tsd_() {} + inline property_merge_45(const property_merge_45& that) : tsd_(that.tsd_) {} + inline property_merge_45& operator=(const property_merge_45& that) { + tsd_ = that.tsd_; + return *this; + } + + inline void insert(const polygon_45_set_data<coordinate_type>& ps, property_type property) { + ps.clean(); + polygon_45_property_merge<big_coord, property_type>::populateMergeSetData(tsd_, ps.begin(), ps.end(), property); + } + template <class GeoObjT> + inline void insert(const GeoObjT& geoObj, property_type property) { + polygon_45_set_data<coordinate_type> ps; + ps.insert(geoObj); + insert(ps, property); + } + + //merge properties of input geometries and store the resulting geometries of regions + //with unique sets of merged properties to polygons sets in a map keyed by sets of properties + // T = std::map<std::set<property_type>, polygon_45_set_data<coordiante_type> > or + // T = std::map<std::vector<property_type>, polygon_45_set_data<coordiante_type> > + template <class result_type> + inline void merge(result_type& result) { + typedef typename result_type::key_type keytype; + typedef std::map<keytype, polygon_45_set_data<big_coord> > bigtype; + bigtype result_big; + polygon_45_property_merge<big_coord, property_type>::performMerge(result_big, tsd_); + std::vector<polygon_45_with_holes_data<big_coord> > polys; + std::vector<rectangle_data<big_coord> > pos_error_rects; + std::vector<rectangle_data<big_coord> > neg_error_rects; + for(typename std::map<keytype, polygon_45_set_data<big_coord> >::iterator itr = result_big.begin(); + itr != result_big.end(); ++itr) { + polys.clear(); + (*itr).second.get(polys); + for(std::size_t i = 0; i < polys.size(); ++i) { + get_error_rects(pos_error_rects, neg_error_rects, polys[i]); + } + (*itr).second += pos_error_rects; + (*itr).second -= neg_error_rects; + (*itr).second.scale_down(2); + result[(*itr).first].insert((*itr).second); + } + } + }; + + //ConnectivityExtraction computes the graph of connectivity between rectangle, polygon and + //polygon set graph nodes where an edge is created whenever the geometry in two nodes overlap + template <typename coordinate_type> + class connectivity_extraction_45 { + private: + typedef typename coordinate_traits<coordinate_type>::manhattan_area_type big_coord; + typedef typename polygon_45_touch<big_coord>::TouchSetData tsd; + tsd tsd_; + unsigned int nodeCount_; + public: + inline connectivity_extraction_45() : tsd_(), nodeCount_(0) {} + inline connectivity_extraction_45(const connectivity_extraction_45& that) : tsd_(that.tsd_), + nodeCount_(that.nodeCount_) {} + inline connectivity_extraction_45& operator=(const connectivity_extraction_45& that) { + tsd_ = that.tsd_; + nodeCount_ = that.nodeCount_; {} + return *this; + } + + //insert a polygon set graph node, the value returned is the id of the graph node + inline unsigned int insert(const polygon_45_set_data<coordinate_type>& ps) { + ps.clean(); + polygon_45_touch<big_coord>::populateTouchSetData(tsd_, ps.begin(), ps.end(), nodeCount_); + return nodeCount_++; + } + template <class GeoObjT> + inline unsigned int insert(const GeoObjT& geoObj) { + polygon_45_set_data<coordinate_type> ps; + ps.insert(geoObj); + return insert(ps); + } + + //extract connectivity and store the edges in the graph + //graph must be indexable by graph node id and the indexed value must be a std::set of + //graph node id + template <class GraphT> + inline void extract(GraphT& graph) { + polygon_45_touch<big_coord>::performTouch(graph, tsd_); + } + }; +} +} +#endif + diff --git a/boost/polygon/polygon_45_set_traits.hpp b/boost/polygon/polygon_45_set_traits.hpp new file mode 100644 index 0000000000..cfc0f98a24 --- /dev/null +++ b/boost/polygon/polygon_45_set_traits.hpp @@ -0,0 +1,146 @@ +/* + 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_POLYGON_45_SET_TRAITS_HPP +#define BOOST_POLYGON_POLYGON_45_SET_TRAITS_HPP +namespace boost { namespace polygon{ + + //default definition of polygon 45 set traits works for any model of polygon 45, polygon 45 with holes or any vector or list thereof + template <typename T> + struct polygon_45_set_traits { + typedef typename get_coordinate_type<T, typename geometry_concept<T>::type >::type coordinate_type; + typedef typename get_iterator_type<T>::type iterator_type; + typedef T operator_arg_type; + + static inline iterator_type begin(const T& polygon_set) { + return get_iterator_type<T>::begin(polygon_set); + } + + static inline iterator_type end(const T& polygon_set) { + return get_iterator_type<T>::end(polygon_set); + } + + static inline bool clean(const T& ) { return false; } + + static inline bool sorted(const T& ) { return false; } + }; + + template <typename T> + struct is_45_polygonal_concept { typedef gtl_no type; }; + template <> + struct is_45_polygonal_concept<polygon_45_concept> { typedef gtl_yes type; }; + template <> + struct is_45_polygonal_concept<polygon_45_with_holes_concept> { typedef gtl_yes type; }; + template <> + struct is_45_polygonal_concept<polygon_45_set_concept> { typedef gtl_yes type; }; + + template <typename T> + struct is_polygon_45_set_type { + typedef typename is_45_polygonal_concept<typename geometry_concept<T>::type>::type type; + }; + template <typename T> + struct is_polygon_45_set_type<std::list<T> > { + typedef typename gtl_or< + typename is_45_polygonal_concept<typename geometry_concept<std::list<T> >::type>::type, + typename is_45_polygonal_concept<typename geometry_concept<typename std::list<T>::value_type>::type>::type>::type type; + }; + template <typename T> + struct is_polygon_45_set_type<std::vector<T> > { + typedef typename gtl_or< + typename is_45_polygonal_concept<typename geometry_concept<std::vector<T> >::type>::type, + typename is_45_polygonal_concept<typename geometry_concept<typename std::vector<T>::value_type>::type>::type>::type type; + }; + + template <typename T> + struct is_mutable_polygon_45_set_type { + typedef typename gtl_same_type<polygon_45_set_concept, typename geometry_concept<T>::type>::type type; + }; + template <typename T> + struct is_mutable_polygon_45_set_type<std::list<T> > { + typedef typename gtl_or< + typename gtl_same_type<polygon_45_set_concept, typename geometry_concept<std::list<T> >::type>::type, + typename is_45_polygonal_concept<typename geometry_concept<typename std::list<T>::value_type>::type>::type>::type type; + }; + template <typename T> + struct is_mutable_polygon_45_set_type<std::vector<T> > { + typedef typename gtl_or< + typename gtl_same_type<polygon_45_set_concept, typename geometry_concept<std::vector<T> >::type>::type, + typename is_45_polygonal_concept<typename geometry_concept<typename std::vector<T>::value_type>::type>::type>::type type; + }; + + template <typename T> + bool fracture_holes_45_by_concept() { return false; } + template <> + inline bool fracture_holes_45_by_concept<polygon_45_concept>() { return true; } + + template <typename T, typename iT> + void get_45_polygons_T(T& t, iT begin, iT end) { + typedef typename polygon_45_set_traits<T>::coordinate_type Unit; + typedef typename geometry_concept<typename T::value_type>::type CType; + typename polygon_45_formation<Unit>::Polygon45Formation pf(fracture_holes_45_by_concept<CType>()); + //std::cout << "FORMING POLYGONS\n"; + pf.scan(t, begin, end); + } + + template <typename T> + struct polygon_45_set_mutable_traits {}; + template <typename T> + struct polygon_45_set_mutable_traits<std::list<T> > { + template <typename input_iterator_type> + static inline void set(std::list<T>& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { + polygon_set.clear(); + polygon_45_set_data<typename polygon_45_set_traits<std::list<T> >::coordinate_type> ps; + ps.insert(input_begin, input_end); + ps.sort(); + ps.clean(); + get_45_polygons_T(polygon_set, ps.begin(), ps.end()); + } + }; + template <typename T> + struct polygon_45_set_mutable_traits<std::vector<T> > { + template <typename input_iterator_type> + static inline void set(std::vector<T>& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { + polygon_set.clear(); + polygon_45_set_data<typename polygon_45_set_traits<std::list<T> >::coordinate_type> ps; + ps.insert(input_begin, input_end); + ps.sort(); + ps.clean(); + get_45_polygons_T(polygon_set, ps.begin(), ps.end()); + } + }; + + template <typename T> + struct polygon_45_set_mutable_traits<polygon_45_set_data<T> > { + template <typename input_iterator_type> + static inline void set(polygon_45_set_data<T>& polygon_set, + input_iterator_type input_begin, input_iterator_type input_end) { + polygon_set.set(input_begin, input_end); + } + }; + template <typename T> + struct polygon_45_set_traits<polygon_45_set_data<T> > { + typedef typename polygon_45_set_data<T>::coordinate_type coordinate_type; + typedef typename polygon_45_set_data<T>::iterator_type iterator_type; + typedef typename polygon_45_set_data<T>::operator_arg_type operator_arg_type; + + static inline iterator_type begin(const polygon_45_set_data<T>& polygon_set) { + return polygon_set.begin(); + } + + static inline iterator_type end(const polygon_45_set_data<T>& polygon_set) { + return polygon_set.end(); + } + + static inline bool clean(const polygon_45_set_data<T>& polygon_set) { polygon_set.clean(); return true; } + + static inline bool sorted(const polygon_45_set_data<T>& polygon_set) { polygon_set.sort(); return true; } + + }; +} +} +#endif + diff --git a/boost/polygon/polygon_45_with_holes_data.hpp b/boost/polygon/polygon_45_with_holes_data.hpp new file mode 100644 index 0000000000..717bbd3a0a --- /dev/null +++ b/boost/polygon/polygon_45_with_holes_data.hpp @@ -0,0 +1,108 @@ +/* + 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_POLYGON_45_WITH_HOLES_DATA_HPP +#define BOOST_POLYGON_POLYGON_45_WITH_HOLES_DATA_HPP +#include "isotropy.hpp" +#include "polygon_45_data.hpp" +namespace boost { namespace polygon{ +struct polygon_45_with_holes_concept; +template <typename T> +class polygon_45_with_holes_data { +public: + typedef polygon_45_with_holes_concept geometry_type; + typedef T coordinate_type; + typedef typename polygon_45_data<T>::iterator_type iterator_type; + typedef typename std::list<polygon_45_data<coordinate_type> >::const_iterator iterator_holes_type; + typedef polygon_45_data<coordinate_type> hole_type; + typedef typename coordinate_traits<T>::coordinate_distance area_type; + typedef point_data<T> point_type; + + // default constructor of point does not initialize x and y + inline polygon_45_with_holes_data() : self_(), holes_() {} //do nothing default constructor + + template<class iT> + inline polygon_45_with_holes_data(iT input_begin, iT input_end) : self_(), holes_() { + set(input_begin, input_end); + } + + template<class iT, typename hiT> + inline polygon_45_with_holes_data(iT input_begin, iT input_end, hiT holes_begin, hiT holes_end) : self_(), holes_() { + set(input_begin, input_end); + set_holes(holes_begin, holes_end); + } + + template<class iT> + inline polygon_45_with_holes_data& set(iT input_begin, iT input_end) { + self_.set(input_begin, input_end); + return *this; + } + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template<class iT> + inline polygon_45_with_holes_data& set_holes(iT input_begin, iT input_end) { + holes_.clear(); //just in case there was some old data there + for( ; input_begin != input_end; ++ input_begin) { + holes_.push_back(hole_type()); + holes_.back().set((*input_begin).begin(), (*input_begin).end()); + } + return *this; + } + + // copy constructor (since we have dynamic memory) + inline polygon_45_with_holes_data(const polygon_45_with_holes_data& that) : self_(that.self_), + holes_(that.holes_) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline polygon_45_with_holes_data& operator=(const polygon_45_with_holes_data& that) { + self_ = that.self_; + holes_ = that.holes_; + return *this; + } + + template <typename T2> + inline polygon_45_with_holes_data& operator=(const T2& rvalue); + + // get begin iterator, returns a pointer to a const coordinate_type + inline const iterator_type begin() const { + return self_.begin(); + } + + // get end iterator, returns a pointer to a const coordinate_type + inline const iterator_type end() const { + return self_.end(); + } + + inline std::size_t size() const { + return self_.size(); + } + + // get begin iterator, returns a pointer to a const polygon + inline const iterator_holes_type begin_holes() const { + return holes_.begin(); + } + + // get end iterator, returns a pointer to a const polygon + inline const iterator_holes_type end_holes() const { + return holes_.end(); + } + + inline std::size_t size_holes() const { + return holes_.size(); + } + +public: + polygon_45_data<coordinate_type> self_; + std::list<hole_type> holes_; +}; + + +} +} +#endif + diff --git a/boost/polygon/polygon_90_data.hpp b/boost/polygon/polygon_90_data.hpp new file mode 100644 index 0000000000..7e1d9695b9 --- /dev/null +++ b/boost/polygon/polygon_90_data.hpp @@ -0,0 +1,80 @@ +/* + 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_POLYGON_90_DATA_HPP +#define BOOST_POLYGON_POLYGON_90_DATA_HPP +namespace boost { namespace polygon{ +struct polygon_90_concept; +template <typename T> +class polygon_90_data { +public: + typedef polygon_90_concept geometry_type; + typedef T coordinate_type; + typedef typename std::vector<coordinate_type>::const_iterator compact_iterator_type; + typedef iterator_compact_to_points<compact_iterator_type, point_data<coordinate_type> > iterator_type; + typedef typename coordinate_traits<T>::area_type area_type; + + inline polygon_90_data() : coords_() {} //do nothing default constructor + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template<class iT> + inline polygon_90_data& set(iT begin_point, iT end_point) { + return set_compact(iterator_points_to_compact<iT, typename std::iterator_traits<iT>::value_type>(begin_point, end_point), + iterator_points_to_compact<iT, typename std::iterator_traits<iT>::value_type>(end_point, end_point)); + } + + template<class iT> + inline polygon_90_data& set_compact(iT input_begin, iT input_end) { + coords_.clear(); //just in case there was some old data there + while(input_begin != input_end) { + coords_.insert(coords_.end(), *input_begin); + ++input_begin; + } + return *this; + } + + // copy constructor (since we have dynamic memory) + inline polygon_90_data(const polygon_90_data& that) : coords_(that.coords_) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline polygon_90_data& operator=(const polygon_90_data& that) { + coords_ = that.coords_; + return *this; + } + + template <typename T2> + inline polygon_90_data& operator=(const T2& rvalue); + + // assignment operator (since we have dynamic memory do a deep copy) + inline bool operator==(const polygon_90_data& that) const { + return coords_ == that.coords_; + } + + // get begin iterator, returns a pointer to a const Unit + inline iterator_type begin() const { return iterator_type(coords_.begin(), coords_.end()); } + + // get end iterator, returns a pointer to a const Unit + inline iterator_type end() const { return iterator_type(coords_.end(), coords_.end()); } + + // get begin iterator, returns a pointer to a const Unit + inline compact_iterator_type begin_compact() const { return coords_.begin(); } + + // get end iterator, returns a pointer to a const Unit + inline compact_iterator_type end_compact() const { return coords_.end(); } + + inline std::size_t size() const { return coords_.size(); } + +private: + std::vector<coordinate_type> coords_; +}; + + +} +} +#endif + diff --git a/boost/polygon/polygon_90_set_concept.hpp b/boost/polygon/polygon_90_set_concept.hpp new file mode 100644 index 0000000000..09d5eee80d --- /dev/null +++ b/boost/polygon/polygon_90_set_concept.hpp @@ -0,0 +1,548 @@ +/* + 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_POLYGON_90_SET_CONCEPT_HPP +#define BOOST_POLYGON_POLYGON_90_SET_CONCEPT_HPP +#include "polygon_90_set_data.hpp" +#include "polygon_90_set_traits.hpp" +namespace boost { namespace polygon{ + + template <typename polygon_set_type> + typename enable_if< typename is_polygon_90_set_type<polygon_set_type>::type, + typename polygon_90_set_traits<polygon_set_type>::iterator_type>::type + begin_90_set_data(const polygon_set_type& polygon_set) { + return polygon_90_set_traits<polygon_set_type>::begin(polygon_set); + } + + template <typename polygon_set_type> + typename enable_if< typename is_polygon_90_set_type<polygon_set_type>::type, + typename polygon_90_set_traits<polygon_set_type>::iterator_type>::type + end_90_set_data(const polygon_set_type& polygon_set) { + return polygon_90_set_traits<polygon_set_type>::end(polygon_set); + } + + template <typename polygon_set_type> + typename enable_if< typename is_polygon_90_set_type<polygon_set_type>::type, + orientation_2d>::type + scanline_orientation(const polygon_set_type& polygon_set) { + return polygon_90_set_traits<polygon_set_type>::orient(polygon_set); + } + + template <typename polygon_set_type> + typename enable_if< typename is_polygon_90_set_type<polygon_set_type>::type, + bool>::type + clean(const polygon_set_type& polygon_set) { + return polygon_90_set_traits<polygon_set_type>::clean(polygon_set); + } + + //assign + template <typename polygon_set_type_1, typename polygon_set_type_2> + typename enable_if < + typename gtl_and< + typename is_mutable_polygon_90_set_type<polygon_set_type_1>::type, + typename is_polygon_90_set_type<polygon_set_type_2>::type>::type, + polygon_set_type_1>::type & + assign(polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { + polygon_90_set_mutable_traits<polygon_set_type_1>::set(lvalue, begin_90_set_data(rvalue), end_90_set_data(rvalue), + scanline_orientation(rvalue)); + return lvalue; + } + + template <typename T1, typename T2> + struct are_not_both_rectangle_concept { typedef gtl_yes type; }; + template <> + struct are_not_both_rectangle_concept<rectangle_concept, rectangle_concept> { typedef gtl_no type; }; + + //equivalence + template <typename polygon_set_type_1, typename polygon_set_type_2> + typename enable_if< typename gtl_and_3< + typename is_polygon_90_set_type<polygon_set_type_1>::type, + typename is_polygon_90_set_type<polygon_set_type_2>::type, + typename are_not_both_rectangle_concept<typename geometry_concept<polygon_set_type_1>::type, + typename geometry_concept<polygon_set_type_2>::type>::type>::type, + bool>::type + equivalence(const polygon_set_type_1& lvalue, + const polygon_set_type_2& rvalue) { + polygon_90_set_data<typename polygon_90_set_traits<polygon_set_type_1>::coordinate_type> ps1; + assign(ps1, lvalue); + polygon_90_set_data<typename polygon_90_set_traits<polygon_set_type_2>::coordinate_type> ps2; + assign(ps2, rvalue); + return ps1 == ps2; + } + + + //get rectangle tiles (slicing orientation is vertical) + template <typename output_container_type, typename polygon_set_type> + typename enable_if< typename gtl_if<typename is_polygon_90_set_type<polygon_set_type>::type>::type, + void>::type + get_rectangles(output_container_type& output, const polygon_set_type& polygon_set) { + clean(polygon_set); + polygon_90_set_data<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> ps(VERTICAL); + assign(ps, polygon_set); + ps.get_rectangles(output); + } + + //get rectangle tiles + template <typename output_container_type, typename polygon_set_type> + typename enable_if< typename gtl_if<typename is_polygon_90_set_type<polygon_set_type>::type>::type, + void>::type + get_rectangles(output_container_type& output, const polygon_set_type& polygon_set, orientation_2d slicing_orientation) { + clean(polygon_set); + polygon_90_set_data<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> ps; + assign(ps, polygon_set); + ps.get_rectangles(output, slicing_orientation); + } + + //get: min_rectangles max_rectangles + template <typename output_container_type, typename polygon_set_type> + typename enable_if <typename gtl_and< + typename is_polygon_90_set_type<polygon_set_type>::type, + typename gtl_same_type<rectangle_concept, + typename geometry_concept + <typename std::iterator_traits + <typename output_container_type::iterator>::value_type>::type>::type>::type, + void>::type + get_max_rectangles(output_container_type& output, const polygon_set_type& polygon_set) { + std::vector<rectangle_data<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> > rects; + assign(rects, polygon_set); + MaxCover<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::getMaxCover(output, rects, scanline_orientation(polygon_set)); + } + + //clear + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + void>::type + clear(polygon_set_type& polygon_set) { + polygon_90_set_data<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> ps(scanline_orientation(polygon_set)); + assign(polygon_set, ps); + } + + //empty + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + bool>::type + empty(const polygon_set_type& polygon_set) { + if(clean(polygon_set)) return begin_90_set_data(polygon_set) == end_90_set_data(polygon_set); + polygon_90_set_data<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> ps; + assign(ps, polygon_set); + ps.clean(); + return ps.empty(); + } + + //extents + template <typename polygon_set_type, typename rectangle_type> + typename enable_if <typename gtl_and< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + bool>::type + extents(rectangle_type& extents_rectangle, + const polygon_set_type& polygon_set) { + typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; + polygon_90_set_data<Unit> ps; + assign(ps, polygon_set); + return ps.extents(extents_rectangle); + } + + //area + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::manhattan_area_type>::type + area(const polygon_set_type& polygon_set) { + typedef rectangle_data<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> rectangle_type; + typedef typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::manhattan_area_type area_type; + std::vector<rectangle_type> rects; + assign(rects, polygon_set); + area_type retval = (area_type)0; + for(std::size_t i = 0; i < rects.size(); ++i) { + retval += (area_type)area(rects[i]); + } + return retval; + } + + //interact + template <typename polygon_set_type_1, typename polygon_set_type_2> + typename enable_if <typename gtl_and< typename is_mutable_polygon_90_set_type<polygon_set_type_1>::type, + typename is_mutable_polygon_90_set_type<polygon_set_type_2>::type>::type, + polygon_set_type_1>::type& + interact(polygon_set_type_1& polygon_set_1, const polygon_set_type_2& polygon_set_2) { + typedef typename polygon_90_set_traits<polygon_set_type_1>::coordinate_type Unit; + polygon_90_set_data<Unit> ps(scanline_orientation(polygon_set_2)); + polygon_90_set_data<Unit> ps2(ps); + ps.insert(polygon_set_1); + ps2.insert(polygon_set_2); + ps.interact(ps2); + assign(polygon_set_1, ps); + return polygon_set_1; + } + + //self_intersect + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + self_intersect(polygon_set_type& polygon_set) { + typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; + polygon_90_set_data<Unit> ps; + assign(ps, polygon_set); + ps.self_intersect(); + assign(polygon_set, ps); + return polygon_set; + } + + //self_xor + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + self_xor(polygon_set_type& polygon_set) { + typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; + polygon_90_set_data<Unit> ps; + assign(ps, polygon_set); + ps.self_xor(); + assign(polygon_set, ps); + return polygon_set; + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + bloat(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { + return bloat(polygon_set, bloating, bloating, bloating, bloating); + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + bloat(polygon_set_type& polygon_set, orientation_2d orient, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { + if(orient == orientation_2d(HORIZONTAL)) + return bloat(polygon_set, bloating, bloating, 0, 0); + return bloat(polygon_set, 0, 0, bloating, bloating); + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + bloat(polygon_set_type& polygon_set, orientation_2d orient, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type low_bloating, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type high_bloating) { + if(orient == orientation_2d(HORIZONTAL)) + return bloat(polygon_set, low_bloating, high_bloating, 0, 0); + return bloat(polygon_set, 0, 0, low_bloating, high_bloating); + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + bloat(polygon_set_type& polygon_set, direction_2d dir, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { + if(dir == direction_2d(EAST)) + return bloat(polygon_set, 0, bloating, 0, 0); + if(dir == direction_2d(WEST)) + return bloat(polygon_set, bloating, 0, 0, 0); + if(dir == direction_2d(SOUTH)) + return bloat(polygon_set, 0, 0, bloating, 0); + return bloat(polygon_set, 0, 0, 0, bloating); + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + bloat(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type west_bloating, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type east_bloating, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type south_bloating, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type north_bloating) { + typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; + polygon_90_set_data<Unit> ps; + assign(ps, polygon_set); + ps.bloat(west_bloating, east_bloating, south_bloating, north_bloating); + ps.clean(); + assign(polygon_set, ps); + return polygon_set; + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + shrink(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type shrinking) { + return shrink(polygon_set, shrinking, shrinking, shrinking, shrinking); + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + shrink(polygon_set_type& polygon_set, orientation_2d orient, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type shrinking) { + if(orient == orientation_2d(HORIZONTAL)) + return shrink(polygon_set, shrinking, shrinking, 0, 0); + return shrink(polygon_set, 0, 0, shrinking, shrinking); + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + shrink(polygon_set_type& polygon_set, orientation_2d orient, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type low_shrinking, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type high_shrinking) { + if(orient == orientation_2d(HORIZONTAL)) + return shrink(polygon_set, low_shrinking, high_shrinking, 0, 0); + return shrink(polygon_set, 0, 0, low_shrinking, high_shrinking); + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + shrink(polygon_set_type& polygon_set, direction_2d dir, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type shrinking) { + if(dir == direction_2d(EAST)) + return shrink(polygon_set, 0, shrinking, 0, 0); + if(dir == direction_2d(WEST)) + return shrink(polygon_set, shrinking, 0, 0, 0); + if(dir == direction_2d(SOUTH)) + return shrink(polygon_set, 0, 0, shrinking, 0); + return shrink(polygon_set, 0, 0, 0, shrinking); + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + shrink(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type west_shrinking, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type east_shrinking, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type south_shrinking, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type north_shrinking) { + typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; + polygon_90_set_data<Unit> ps; + assign(ps, polygon_set); + ps.shrink(west_shrinking, east_shrinking, south_shrinking, north_shrinking); + ps.clean(); + assign(polygon_set, ps); + return polygon_set; + } + + template <typename polygon_set_type, typename coord_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + resize(polygon_set_type& polygon_set, coord_type resizing) { + typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; + if(resizing > 0) { + return bloat(polygon_set, resizing); + } + if(resizing < 0) { + return shrink(polygon_set, -resizing); + } + return polygon_set; + } + + //positive or negative values allow for any and all directions of sizing + template <typename polygon_set_type, typename coord_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + resize(polygon_set_type& polygon_set, coord_type west, coord_type east, coord_type south, coord_type north) { + typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; + polygon_90_set_data<Unit> ps; + assign(ps, polygon_set); + ps.resize(west, east, south, north); + assign(polygon_set, ps); + return polygon_set; + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + grow_and(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { + return grow_and(polygon_set, bloating, bloating, bloating, bloating); + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + grow_and(polygon_set_type& polygon_set, orientation_2d orient, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { + if(orient == orientation_2d(HORIZONTAL)) + return grow_and(polygon_set, bloating, bloating, 0, 0); + return grow_and(polygon_set, 0, 0, bloating, bloating); + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + grow_and(polygon_set_type& polygon_set, orientation_2d orient, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type low_bloating, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type high_bloating) { + if(orient == orientation_2d(HORIZONTAL)) + return grow_and(polygon_set, low_bloating, high_bloating, 0, 0); + return grow_and(polygon_set, 0, 0, low_bloating, high_bloating); + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + grow_and(polygon_set_type& polygon_set, direction_2d dir, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { + if(dir == direction_2d(EAST)) + return grow_and(polygon_set, 0, bloating, 0, 0); + if(dir == direction_2d(WEST)) + return grow_and(polygon_set, bloating, 0, 0, 0); + if(dir == direction_2d(SOUTH)) + return grow_and(polygon_set, 0, 0, bloating, 0); + return grow_and(polygon_set, 0, 0, 0, bloating); + } + + template <typename polygon_set_type> + typename enable_if< typename gtl_if<typename is_mutable_polygon_90_set_type<polygon_set_type>::type>::type, + polygon_set_type>::type & + grow_and(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type west_bloating, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type east_bloating, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type south_bloating, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type north_bloating) { + typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; + std::vector<polygon_90_data<Unit> > polys; + assign(polys, polygon_set); + clear(polygon_set); + polygon_90_set_data<Unit> ps(scanline_orientation(polygon_set)); + for(std::size_t i = 0; i < polys.size(); ++i) { + polygon_90_set_data<Unit> tmpPs(scanline_orientation(polygon_set)); + tmpPs.insert(polys[i]); + bloat(tmpPs, west_bloating, east_bloating, south_bloating, north_bloating); + tmpPs.clean(); //apply implicit OR on tmp polygon set + ps.insert(tmpPs); + } + self_intersect(ps); + assign(polygon_set, ps); + return polygon_set; + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + scale_up(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> + ::unsigned_area_type factor) { + typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; + polygon_90_set_data<Unit> ps; + assign(ps, polygon_set); + ps.scale_up(factor); + assign(polygon_set, ps); + return polygon_set; + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + scale_down(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type> + ::unsigned_area_type factor) { + typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; + polygon_90_set_data<Unit> ps; + assign(ps, polygon_set); + ps.scale_down(factor); + assign(polygon_set, ps); + return polygon_set; + } + + template <typename polygon_set_type, typename scaling_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + scale(polygon_set_type& polygon_set, + const scaling_type& scaling) { + typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; + polygon_90_set_data<Unit> ps; + assign(ps, polygon_set); + ps.scale(scaling); + assign(polygon_set, ps); + return polygon_set; + } + + //move + template <typename polygon_set_type> + polygon_set_type& + move(polygon_set_type& polygon_set, + orientation_2d orient, typename polygon_90_set_traits<polygon_set_type>::coordinate_type displacement, + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type>::type * = 0) { + if(orient == HORIZONTAL) + return move(polygon_set, displacement, 0); + else + return move(polygon_set, 0, displacement); + } + + template <typename polygon_set_type> + polygon_set_type& + move(polygon_set_type& polygon_set, typename polygon_90_set_traits<polygon_set_type>::coordinate_type x_displacement, + typename polygon_90_set_traits<polygon_set_type>::coordinate_type y_displacement, + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type>::type * = 0 + ) { + typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; + polygon_90_set_data<Unit> ps; + assign(ps, polygon_set); + ps.move(x_displacement, y_displacement); + ps.clean(); + assign(polygon_set, ps); + return polygon_set; + } + + //transform + template <typename polygon_set_type, typename transformation_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + transform(polygon_set_type& polygon_set, + const transformation_type& transformation) { + typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; + polygon_90_set_data<Unit> ps; + assign(ps, polygon_set); + ps.transform(transformation); + ps.clean(); + assign(polygon_set, ps); + return polygon_set; + typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; + } + + //keep + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_90_set_type<polygon_set_type>::type, + polygon_set_type>::type & + keep(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type min_area, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type max_area, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type min_width, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type max_width, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type min_height, + typename coordinate_traits<typename polygon_90_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type max_height) { + typedef typename polygon_90_set_traits<polygon_set_type>::coordinate_type Unit; + typedef typename coordinate_traits<Unit>::unsigned_area_type uat; + std::list<polygon_90_data<Unit> > polys; + assign(polys, polygon_set); + clear(polygon_set); + typename std::list<polygon_90_data<Unit> >::iterator itr_nxt; + for(typename std::list<polygon_90_data<Unit> >::iterator itr = polys.begin(); itr != polys.end(); itr = itr_nxt){ + itr_nxt = itr; + ++itr_nxt; + rectangle_data<Unit> bbox; + extents(bbox, *itr); + uat pwidth = delta(bbox, HORIZONTAL); + if(pwidth > min_width && pwidth <= max_width){ + uat pheight = delta(bbox, VERTICAL); + if(pheight > min_height && pheight <= max_height){ + uat parea = area(*itr); + if(parea <= max_area && parea >= min_area) { + continue; + } + } + } + polys.erase(itr); + } + assign(polygon_set, polys); + return polygon_set; + } + + +} +} +#include "detail/polygon_90_set_view.hpp" +#endif diff --git a/boost/polygon/polygon_90_set_data.hpp b/boost/polygon/polygon_90_set_data.hpp new file mode 100644 index 0000000000..151cb9d259 --- /dev/null +++ b/boost/polygon/polygon_90_set_data.hpp @@ -0,0 +1,957 @@ +/* + 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_POLYGON_90_SET_DATA_HPP +#define BOOST_POLYGON_POLYGON_90_SET_DATA_HPP +#include "isotropy.hpp" +#include "point_concept.hpp" +#include "point_3d_concept.hpp" +#include "transform.hpp" +#include "interval_concept.hpp" +#include "rectangle_concept.hpp" +#include "detail/iterator_points_to_compact.hpp" +#include "detail/iterator_compact_to_points.hpp" +#include "polygon_traits.hpp" + +//manhattan boolean algorithms +#include "detail/boolean_op.hpp" +#include "detail/polygon_formation.hpp" +#include "detail/rectangle_formation.hpp" +#include "detail/max_cover.hpp" +#include "detail/property_merge.hpp" +#include "detail/polygon_90_touch.hpp" +#include "detail/iterator_geometry_to_set.hpp" + +namespace boost { namespace polygon{ + template <typename ltype, typename rtype, typename op_type> + class polygon_90_set_view; + + template <typename T> + class polygon_90_set_data { + public: + typedef T coordinate_type; + typedef std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > > value_type; + typedef typename std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::const_iterator iterator_type; + typedef polygon_90_set_data operator_arg_type; + + // default constructor + inline polygon_90_set_data() : orient_(HORIZONTAL), data_(), dirty_(false), unsorted_(false) {} + + // constructor + inline polygon_90_set_data(orientation_2d orient) : orient_(orient), data_(), dirty_(false), unsorted_(false) {} + + // constructor from an iterator pair over vertex data + template <typename iT> + inline polygon_90_set_data(orientation_2d orient, iT input_begin, iT input_end) : + orient_(HORIZONTAL), data_(), dirty_(false), unsorted_(false) { + dirty_ = true; + unsorted_ = true; + for( ; input_begin != input_end; ++input_begin) { insert(*input_begin); } + } + + // copy constructor + inline polygon_90_set_data(const polygon_90_set_data& that) : + orient_(that.orient_), data_(that.data_), dirty_(that.dirty_), unsorted_(that.unsorted_) {} + + template <typename ltype, typename rtype, typename op_type> + inline polygon_90_set_data(const polygon_90_set_view<ltype, rtype, op_type>& that); + + // copy with orientation change constructor + inline polygon_90_set_data(orientation_2d orient, const polygon_90_set_data& that) : + orient_(orient), data_(), dirty_(false), unsorted_(false) { + insert(that, false, that.orient_); + } + + // destructor + inline ~polygon_90_set_data() {} + + // assignement operator + inline polygon_90_set_data& operator=(const polygon_90_set_data& that) { + if(this == &that) return *this; + orient_ = that.orient_; + data_ = that.data_; + dirty_ = that.dirty_; + unsorted_ = that.unsorted_; + return *this; + } + + template <typename ltype, typename rtype, typename op_type> + inline polygon_90_set_data& operator=(const polygon_90_set_view<ltype, rtype, op_type>& that); + + template <typename geometry_object> + inline polygon_90_set_data& operator=(const geometry_object& geometry) { + data_.clear(); + insert(geometry); + return *this; + } + + // insert iterator range + inline void insert(iterator_type input_begin, iterator_type input_end, orientation_2d orient = HORIZONTAL) { + if(input_begin == input_end || (!data_.empty() && &(*input_begin) == &(*(data_.begin())))) return; + dirty_ = true; + unsorted_ = true; + if(orient == orient_) + data_.insert(data_.end(), input_begin, input_end); + else { + for( ; input_begin != input_end; ++input_begin) { + insert(*input_begin, false, orient); + } + } + } + + // insert iterator range + template <typename iT> + inline void insert(iT input_begin, iT input_end, orientation_2d orient = HORIZONTAL) { + if(input_begin == input_end) return; + dirty_ = true; + unsorted_ = true; + for( ; input_begin != input_end; ++input_begin) { + insert(*input_begin, false, orient); + } + } + + inline void insert(const polygon_90_set_data& polygon_set) { + insert(polygon_set.begin(), polygon_set.end(), polygon_set.orient()); + } + + inline void insert(const std::pair<std::pair<point_data<coordinate_type>, point_data<coordinate_type> >, int>& edge, bool is_hole = false, + orientation_2d orient = HORIZONTAL) { + std::pair<coordinate_type, std::pair<coordinate_type, int> > vertex; + vertex.first = edge.first.first.x(); + vertex.second.first = edge.first.first.y(); + vertex.second.second = edge.second * (is_hole ? -1 : 1); + insert(vertex, false, VERTICAL); + vertex.first = edge.first.second.x(); + vertex.second.first = edge.first.second.y(); + vertex.second.second *= -1; + insert(vertex, false, VERTICAL); + } + + template <typename geometry_type> + inline void insert(const geometry_type& geometry_object, bool is_hole = false, orientation_2d = HORIZONTAL) { + iterator_geometry_to_set<typename geometry_concept<geometry_type>::type, geometry_type> + begin_input(geometry_object, LOW, orient_, is_hole), end_input(geometry_object, HIGH, orient_, is_hole); + insert(begin_input, end_input, orient_); + } + + inline void insert(const std::pair<coordinate_type, std::pair<coordinate_type, int> >& vertex, bool is_hole = false, + orientation_2d orient = HORIZONTAL) { + data_.push_back(vertex); + if(orient != orient_) std::swap(data_.back().first, data_.back().second.first); + if(is_hole) data_.back().second.second *= -1; + dirty_ = true; + unsorted_ = true; + } + + inline void insert(coordinate_type major_coordinate, const std::pair<interval_data<coordinate_type>, int>& edge) { + std::pair<coordinate_type, std::pair<coordinate_type, int> > vertex; + vertex.first = major_coordinate; + vertex.second.first = edge.first.get(LOW); + vertex.second.second = edge.second; + insert(vertex, false, orient_); + vertex.second.first = edge.first.get(HIGH); + vertex.second.second *= -1; + insert(vertex, false, orient_); + } + + template <typename output_container> + inline void get(output_container& output) const { + get_dispatch(output, typename geometry_concept<typename output_container::value_type>::type()); + } + + template <typename output_container> + inline void get_polygons(output_container& output) const { + get_dispatch(output, polygon_90_concept()); + } + + template <typename output_container> + inline void get_rectangles(output_container& output) const { + clean(); + form_rectangles(output, data_.begin(), data_.end(), orient_, rectangle_concept()); + } + + template <typename output_container> + inline void get_rectangles(output_container& output, orientation_2d slicing_orientation) const { + if(slicing_orientation == orient_) { + get_rectangles(output); + } else { + polygon_90_set_data<coordinate_type> ps(*this); + ps.transform(axis_transformation(axis_transformation::SWAP_XY)); + output_container result; + ps.get_rectangles(result); + for(typename output_container::iterator itr = result.begin(); itr != result.end(); ++itr) { + ::boost::polygon::transform(*itr, axis_transformation(axis_transformation::SWAP_XY)); + } + output.insert(output.end(), result.begin(), result.end()); + } + } + + // equivalence operator + inline bool operator==(const polygon_90_set_data& p) const { + if(orient_ == p.orient()) { + clean(); + p.clean(); + return data_ == p.data_; + } else { + return false; + } + } + + // inequivalence operator + inline bool operator!=(const polygon_90_set_data& p) const { + return !((*this) == p); + } + + // get iterator to begin vertex data + inline iterator_type begin() const { + return data_.begin(); + } + + // get iterator to end vertex data + inline iterator_type end() const { + return data_.end(); + } + + const value_type& value() const { + return data_; + } + + // clear the contents of the polygon_90_set_data + inline void clear() { data_.clear(); dirty_ = unsorted_ = false; } + + // find out if Polygon set is empty + inline bool empty() const { clean(); return data_.empty(); } + + // get the Polygon set size in vertices + inline std::size_t size() const { clean(); return data_.size(); } + + // get the current Polygon set capacity in vertices + inline std::size_t capacity() const { return data_.capacity(); } + + // reserve size of polygon set in vertices + inline void reserve(std::size_t size) { return data_.reserve(size); } + + // find out if Polygon set is sorted + inline bool sorted() const { return !unsorted_; } + + // find out if Polygon set is clean + inline bool dirty() const { return dirty_; } + + // get the scanline orientation of the polygon set + inline orientation_2d orient() const { return orient_; } + + // Start BM + // The problem: If we have two polygon sets with two different scanline orientations: + // I tried changing the orientation of one to coincide with other (If not, resulting boolean operation + // produces spurious results). + // First I tried copying polygon data from one of the sets into another set with corrected orientation + // using one of the copy constructor that takes in orientation (see somewhere above in this file) --> copy constructor throws error + // Then I tried another approach:(see below). This approach also fails to produce the desired results when test case is run. + // Here is the part that beats me: If I comment out the whole section, I can do all the operations (^=, -=, &= )these commented out + // operations perform. So then why do we need them?. Hence, I commented out this whole section. + // End BM + // polygon_90_set_data<coordinate_type>& operator-=(const polygon_90_set_data& that) { + // sort(); + // that.sort(); + // value_type data; + // std::swap(data, data_); + // applyBooleanBinaryOp(data.begin(), data.end(), + // that.begin(), that.end(), boolean_op::BinaryCount<boolean_op::BinaryNot>()); + // return *this; + // } + // polygon_90_set_data<coordinate_type>& operator^=(const polygon_90_set_data& that) { + // sort(); + // that.sort(); + // value_type data; + // std::swap(data, data_); + // applyBooleanBinaryOp(data.begin(), data.end(), + // that.begin(), that.end(), boolean_op::BinaryCount<boolean_op::BinaryXor>()); + // return *this; + // } + // polygon_90_set_data<coordinate_type>& operator&=(const polygon_90_set_data& that) { + // sort(); + // that.sort(); + // value_type data; + // std::swap(data, data_); + // applyBooleanBinaryOp(data.begin(), data.end(), + // that.begin(), that.end(), boolean_op::BinaryCount<boolean_op::BinaryAnd>()); + // return *this; + // } + // polygon_90_set_data<coordinate_type>& operator|=(const polygon_90_set_data& that) { + // insert(that); + // return *this; + // } + + void clean() const { + sort(); + if(dirty_) { + boolean_op::default_arg_workaround<int>::applyBooleanOr(data_); + dirty_ = false; + } + } + + void sort() const{ + if(unsorted_) { + gtlsort(data_.begin(), data_.end()); + unsorted_ = false; + } + } + + template <typename input_iterator_type> + void set(input_iterator_type input_begin, input_iterator_type input_end, orientation_2d orient) { + data_.clear(); + data_.insert(data_.end(), input_begin, input_end); + orient_ = orient; + dirty_ = true; + unsorted_ = true; + } + + void set(const value_type& value, orientation_2d orient) { + data_ = value; + orient_ = orient; + dirty_ = true; + unsorted_ = true; + } + + //extents + template <typename rectangle_type> + bool + extents(rectangle_type& extents_rectangle) const { + clean(); + if(data_.empty()) return false; + if(orient_ == HORIZONTAL) + set_points(extents_rectangle, point_data<coordinate_type>(data_[0].second.first, data_[0].first), + point_data<coordinate_type>(data_[data_.size() - 1].second.first, data_[data_.size() - 1].first)); + else + set_points(extents_rectangle, point_data<coordinate_type>(data_[0].first, data_[0].second.first), + point_data<coordinate_type>(data_[data_.size() - 1].first, data_[data_.size() - 1].second.first)); + for(std::size_t i = 1; i < data_.size() - 1; ++i) { + if(orient_ == HORIZONTAL) + encompass(extents_rectangle, point_data<coordinate_type>(data_[i].second.first, data_[i].first)); + else + encompass(extents_rectangle, point_data<coordinate_type>(data_[i].first, data_[i].second.first)); + } + return true; + } + + polygon_90_set_data& + bloat2(typename coordinate_traits<coordinate_type>::unsigned_area_type west_bloating, + typename coordinate_traits<coordinate_type>::unsigned_area_type east_bloating, + typename coordinate_traits<coordinate_type>::unsigned_area_type south_bloating, + typename coordinate_traits<coordinate_type>::unsigned_area_type north_bloating) { + std::vector<rectangle_data<coordinate_type> > rects; + clean(); + rects.reserve(data_.size() / 2); + get(rects); + rectangle_data<coordinate_type> convolutionRectangle(interval_data<coordinate_type>(-((coordinate_type)west_bloating), + (coordinate_type)east_bloating), + interval_data<coordinate_type>(-((coordinate_type)south_bloating), + (coordinate_type)north_bloating)); + for(typename std::vector<rectangle_data<coordinate_type> >::iterator itr = rects.begin(); + itr != rects.end(); ++itr) { + convolve(*itr, convolutionRectangle); + } + clear(); + insert(rects.begin(), rects.end()); + return *this; + } + + static void modify_pt(point_data<coordinate_type>& pt, const point_data<coordinate_type>& prev_pt, + const point_data<coordinate_type>& current_pt, const point_data<coordinate_type>& next_pt, + coordinate_type west_bloating, + coordinate_type east_bloating, + coordinate_type south_bloating, + coordinate_type north_bloating) { + bool pxl = prev_pt.x() < current_pt.x(); + bool pyl = prev_pt.y() < current_pt.y(); + bool nxl = next_pt.x() < current_pt.x(); + bool nyl = next_pt.y() < current_pt.y(); + bool pxg = prev_pt.x() > current_pt.x(); + bool pyg = prev_pt.y() > current_pt.y(); + bool nxg = next_pt.x() > current_pt.x(); + bool nyg = next_pt.y() > current_pt.y(); + //two of the four if statements will execute + if(pxl) + pt.y(current_pt.y() - south_bloating); + if(pxg) + pt.y(current_pt.y() + north_bloating); + if(nxl) + pt.y(current_pt.y() + north_bloating); + if(nxg) + pt.y(current_pt.y() - south_bloating); + if(pyl) + pt.x(current_pt.x() + east_bloating); + if(pyg) + pt.x(current_pt.x() - west_bloating); + if(nyl) + pt.x(current_pt.x() - west_bloating); + if(nyg) + pt.x(current_pt.x() + east_bloating); + } + static void resize_poly_up(std::vector<point_data<coordinate_type> >& poly, + coordinate_type west_bloating, + coordinate_type east_bloating, + coordinate_type south_bloating, + coordinate_type north_bloating) { + point_data<coordinate_type> first_pt = poly[0]; + point_data<coordinate_type> second_pt = poly[1]; + point_data<coordinate_type> prev_pt = poly[0]; + point_data<coordinate_type> current_pt = poly[1]; + for(std::size_t i = 2; i < poly.size(); ++i) { + point_data<coordinate_type> next_pt = poly[i]; + modify_pt(poly[i-1], prev_pt, current_pt, next_pt, west_bloating, east_bloating, south_bloating, north_bloating); + prev_pt = current_pt; + current_pt = next_pt; + } + point_data<coordinate_type> next_pt = first_pt; + modify_pt(poly.back(), prev_pt, current_pt, next_pt, west_bloating, east_bloating, south_bloating, north_bloating); + prev_pt = current_pt; + current_pt = next_pt; + next_pt = second_pt; + modify_pt(poly[0], prev_pt, current_pt, next_pt, west_bloating, east_bloating, south_bloating, north_bloating); + remove_colinear_pts(poly); + } + static bool resize_poly_down(std::vector<point_data<coordinate_type> >& poly, + coordinate_type west_shrinking, + coordinate_type east_shrinking, + coordinate_type south_shrinking, + coordinate_type north_shrinking) { + rectangle_data<coordinate_type> extents_rectangle; + set_points(extents_rectangle, poly[0], poly[0]); + point_data<coordinate_type> first_pt = poly[0]; + point_data<coordinate_type> second_pt = poly[1]; + point_data<coordinate_type> prev_pt = poly[0]; + point_data<coordinate_type> current_pt = poly[1]; + encompass(extents_rectangle, current_pt); + for(int i = 2; i < poly.size(); ++i) { + point_data<coordinate_type> next_pt = poly[i]; + encompass(extents_rectangle, next_pt); + modify_pt(poly[i-1], prev_pt, current_pt, next_pt, west_shrinking, east_shrinking, south_shrinking, north_shrinking); + prev_pt = current_pt; + current_pt = next_pt; + } + if(delta(extents_rectangle, HORIZONTAL) < std::abs(west_shrinking + east_shrinking)) + return false; + if(delta(extents_rectangle, VERTICAL) < std::abs(north_shrinking + south_shrinking)) + return false; + point_data<coordinate_type> next_pt = first_pt; + modify_pt(poly.back(), prev_pt, current_pt, next_pt, west_shrinking, east_shrinking, south_shrinking, north_shrinking); + prev_pt = current_pt; + current_pt = next_pt; + next_pt = second_pt; + modify_pt(poly[0], prev_pt, current_pt, next_pt, west_shrinking, east_shrinking, south_shrinking, north_shrinking); + return remove_colinear_pts(poly); + } + + static bool remove_colinear_pts(std::vector<point_data<coordinate_type> >& poly) { + bool found_colinear = true; + while(found_colinear && poly.size() >= 4) { + found_colinear = false; + typename std::vector<point_data<coordinate_type> >::iterator itr = poly.begin(); + itr += poly.size() - 1; //get last element position + typename std::vector<point_data<coordinate_type> >::iterator itr2 = poly.begin(); + typename std::vector<point_data<coordinate_type> >::iterator itr3 = itr2; + ++itr3; + std::size_t count = 0; + for( ; itr3 < poly.end(); ++itr3) { + if(((*itr).x() == (*itr2).x() && (*itr).x() == (*itr3).x()) || + ((*itr).y() == (*itr2).y() && (*itr).y() == (*itr3).y()) ) { + ++count; + found_colinear = true; + } else { + itr = itr2; + ++itr2; + } + *itr2 = *itr3; + } + itr3 = poly.begin(); + if(((*itr).x() == (*itr2).x() && (*itr).x() == (*itr3).x()) || + ((*itr).y() == (*itr2).y() && (*itr).y() == (*itr3).y()) ) { + ++count; + found_colinear = true; + } + poly.erase(poly.end() - count, poly.end()); + } + return poly.size() >= 4; + } + + polygon_90_set_data& + bloat(typename coordinate_traits<coordinate_type>::unsigned_area_type west_bloating, + typename coordinate_traits<coordinate_type>::unsigned_area_type east_bloating, + typename coordinate_traits<coordinate_type>::unsigned_area_type south_bloating, + typename coordinate_traits<coordinate_type>::unsigned_area_type north_bloating) { + std::list<polygon_45_with_holes_data<coordinate_type> > polys; + get(polys); + clear(); + for(typename std::list<polygon_45_with_holes_data<coordinate_type> >::iterator itr = polys.begin(); + itr != polys.end(); ++itr) { + //polygon_90_set_data<coordinate_type> psref; + //psref.insert(view_as<polygon_90_concept>((*itr).self_)); + //rectangle_data<coordinate_type> prerect; + //psref.extents(prerect); + resize_poly_up((*itr).self_.coords_, west_bloating, east_bloating, south_bloating, north_bloating); + iterator_geometry_to_set<polygon_90_concept, view_of<polygon_90_concept, polygon_45_data<coordinate_type> > > + begin_input(view_as<polygon_90_concept>((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE), + end_input(view_as<polygon_90_concept>((*itr).self_), HIGH, orient_, false, true, COUNTERCLOCKWISE); + insert(begin_input, end_input, orient_); + //polygon_90_set_data<coordinate_type> pstest; + //pstest.insert(view_as<polygon_90_concept>((*itr).self_)); + //psref.bloat2(west_bloating, east_bloating, south_bloating, north_bloating); + //if(!equivalence(psref, pstest)) { + // std::cout << "test failed\n"; + //} + for(typename std::list<polygon_45_data<coordinate_type> >::iterator itrh = (*itr).holes_.begin(); + itrh != (*itr).holes_.end(); ++itrh) { + //rectangle_data<coordinate_type> rect; + //psref.extents(rect); + //polygon_90_set_data<coordinate_type> psrefhole; + //psrefhole.insert(prerect); + //psrefhole.insert(view_as<polygon_90_concept>(*itrh), true); + //polygon_45_data<coordinate_type> testpoly(*itrh); + if(resize_poly_down((*itrh).coords_, west_bloating, east_bloating, south_bloating, north_bloating)) { + iterator_geometry_to_set<polygon_90_concept, view_of<polygon_90_concept, polygon_45_data<coordinate_type> > > + begin_input2(view_as<polygon_90_concept>(*itrh), LOW, orient_, true, true), + end_input2(view_as<polygon_90_concept>(*itrh), HIGH, orient_, true, true); + insert(begin_input2, end_input2, orient_); + //polygon_90_set_data<coordinate_type> pstesthole; + //pstesthole.insert(rect); + //iterator_geometry_to_set<polygon_90_concept, view_of<polygon_90_concept, polygon_45_data<coordinate_type> > > + // begin_input2(view_as<polygon_90_concept>(*itrh), LOW, orient_, true, true); + //pstesthole.insert(begin_input2, end_input, orient_); + //psrefhole.bloat2(west_bloating, east_bloating, south_bloating, north_bloating); + //if(!equivalence(psrefhole, pstesthole)) { + // std::cout << (winding(testpoly) == CLOCKWISE) << std::endl; + // std::cout << (winding(*itrh) == CLOCKWISE) << std::endl; + // polygon_90_set_data<coordinate_type> c(psrefhole); + // c.clean(); + // polygon_90_set_data<coordinate_type> a(pstesthole); + // polygon_90_set_data<coordinate_type> b(pstesthole); + // a.sort(); + // b.clean(); + // std::cout << "test hole failed\n"; + // //std::cout << testpoly << std::endl; + //} + } + } + } + return *this; + } + + polygon_90_set_data& + shrink(typename coordinate_traits<coordinate_type>::unsigned_area_type west_shrinking, + typename coordinate_traits<coordinate_type>::unsigned_area_type east_shrinking, + typename coordinate_traits<coordinate_type>::unsigned_area_type south_shrinking, + typename coordinate_traits<coordinate_type>::unsigned_area_type north_shrinking) { + std::list<polygon_45_with_holes_data<coordinate_type> > polys; + get(polys); + clear(); + for(typename std::list<polygon_45_with_holes_data<coordinate_type> >::iterator itr = polys.begin(); + itr != polys.end(); ++itr) { + //polygon_90_set_data<coordinate_type> psref; + //psref.insert(view_as<polygon_90_concept>((*itr).self_)); + //rectangle_data<coordinate_type> prerect; + //psref.extents(prerect); + //polygon_45_data<coordinate_type> testpoly((*itr).self_); + if(resize_poly_down((*itr).self_.coords_, -west_shrinking, -east_shrinking, -south_shrinking, -north_shrinking)) { + iterator_geometry_to_set<polygon_90_concept, view_of<polygon_90_concept, polygon_45_data<coordinate_type> > > + begin_input(view_as<polygon_90_concept>((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE), + end_input(view_as<polygon_90_concept>((*itr).self_), HIGH, orient_, false, true, COUNTERCLOCKWISE); + insert(begin_input, end_input, orient_); + //iterator_geometry_to_set<polygon_90_concept, view_of<polygon_90_concept, polygon_45_data<coordinate_type> > > + // begin_input2(view_as<polygon_90_concept>((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE); + //polygon_90_set_data<coordinate_type> pstest; + //pstest.insert(begin_input2, end_input, orient_); + //psref.shrink2(west_shrinking, east_shrinking, south_shrinking, north_shrinking); + //if(!equivalence(psref, pstest)) { + // std::cout << "test failed\n"; + //} + for(typename std::list<polygon_45_data<coordinate_type> >::iterator itrh = (*itr).holes_.begin(); + itrh != (*itr).holes_.end(); ++itrh) { + //rectangle_data<coordinate_type> rect; + //psref.extents(rect); + //polygon_90_set_data<coordinate_type> psrefhole; + //psrefhole.insert(prerect); + //psrefhole.insert(view_as<polygon_90_concept>(*itrh), true); + //polygon_45_data<coordinate_type> testpoly(*itrh); + resize_poly_up((*itrh).coords_, -west_shrinking, -east_shrinking, -south_shrinking, -north_shrinking); + iterator_geometry_to_set<polygon_90_concept, view_of<polygon_90_concept, polygon_45_data<coordinate_type> > > + begin_input2(view_as<polygon_90_concept>(*itrh), LOW, orient_, true, true), + end_input2(view_as<polygon_90_concept>(*itrh), HIGH, orient_, true, true); + insert(begin_input2, end_input2, orient_); + //polygon_90_set_data<coordinate_type> pstesthole; + //pstesthole.insert(rect); + //iterator_geometry_to_set<polygon_90_concept, view_of<polygon_90_concept, polygon_45_data<coordinate_type> > > + // begin_input2(view_as<polygon_90_concept>(*itrh), LOW, orient_, true, true); + //pstesthole.insert(begin_input2, end_input, orient_); + //psrefhole.shrink2(west_shrinking, east_shrinking, south_shrinking, north_shrinking); + //if(!equivalence(psrefhole, pstesthole)) { + // std::cout << (winding(testpoly) == CLOCKWISE) << std::endl; + // std::cout << (winding(*itrh) == CLOCKWISE) << std::endl; + // polygon_90_set_data<coordinate_type> c(psrefhole); + // c.clean(); + // polygon_90_set_data<coordinate_type> a(pstesthole); + // polygon_90_set_data<coordinate_type> b(pstesthole); + // a.sort(); + // b.clean(); + // std::cout << "test hole failed\n"; + // //std::cout << testpoly << std::endl; + //} + } + } + } + return *this; + } + + polygon_90_set_data& + shrink2(typename coordinate_traits<coordinate_type>::unsigned_area_type west_shrinking, + typename coordinate_traits<coordinate_type>::unsigned_area_type east_shrinking, + typename coordinate_traits<coordinate_type>::unsigned_area_type south_shrinking, + typename coordinate_traits<coordinate_type>::unsigned_area_type north_shrinking) { + rectangle_data<coordinate_type> externalBoundary; + if(!extents(externalBoundary)) return *this; + ::boost::polygon::bloat(externalBoundary, 10); //bloat by diferential ammount + //insert a hole that encompasses the data + insert(externalBoundary, true); //note that the set is in a dirty state now + sort(); //does not apply implicit OR operation + std::vector<rectangle_data<coordinate_type> > rects; + rects.reserve(data_.size() / 2); + //begin does not apply implicit or operation, this is a dirty range + form_rectangles(rects, data_.begin(), data_.end(), orient_, rectangle_concept()); + clear(); + rectangle_data<coordinate_type> convolutionRectangle(interval_data<coordinate_type>(-((coordinate_type)east_shrinking), + (coordinate_type)west_shrinking), + interval_data<coordinate_type>(-((coordinate_type)north_shrinking), + (coordinate_type)south_shrinking)); + for(typename std::vector<rectangle_data<coordinate_type> >::iterator itr = rects.begin(); + itr != rects.end(); ++itr) { + rectangle_data<coordinate_type>& rect = *itr; + convolve(rect, convolutionRectangle); + //insert rectangle as a hole + insert(rect, true); + } + convolve(externalBoundary, convolutionRectangle); + //insert duplicate of external boundary as solid to cancel out the external hole boundaries + insert(externalBoundary); + clean(); //we have negative values in the set, so we need to apply an OR operation to make it valid input to a boolean + return *this; + } + + polygon_90_set_data& + shrink(direction_2d dir, typename coordinate_traits<coordinate_type>::unsigned_area_type shrinking) { + if(dir == WEST) + return shrink(shrinking, 0, 0, 0); + if(dir == EAST) + return shrink(0, shrinking, 0, 0); + if(dir == SOUTH) + return shrink(0, 0, shrinking, 0); + return shrink(0, 0, 0, shrinking); + } + + polygon_90_set_data& + bloat(direction_2d dir, typename coordinate_traits<coordinate_type>::unsigned_area_type shrinking) { + if(dir == WEST) + return bloat(shrinking, 0, 0, 0); + if(dir == EAST) + return bloat(0, shrinking, 0, 0); + if(dir == SOUTH) + return bloat(0, 0, shrinking, 0); + return bloat(0, 0, 0, shrinking); + } + + polygon_90_set_data& + resize(coordinate_type west, coordinate_type east, coordinate_type south, coordinate_type north); + + polygon_90_set_data& move(coordinate_type x_delta, coordinate_type y_delta) { + for(typename std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::iterator + itr = data_.begin(); itr != data_.end(); ++itr) { + if(orient_ == orientation_2d(VERTICAL)) { + (*itr).first += x_delta; + (*itr).second.first += y_delta; + } else { + (*itr).second.first += x_delta; + (*itr).first += y_delta; + } + } + return *this; + } + + // transform set + template <typename transformation_type> + polygon_90_set_data& transform(const transformation_type& transformation) { + direction_2d dir1, dir2; + transformation.get_directions(dir1, dir2); + int sign = dir1.get_sign() * dir2.get_sign(); + for(typename std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::iterator + itr = data_.begin(); itr != data_.end(); ++itr) { + if(orient_ == orientation_2d(VERTICAL)) { + transformation.transform((*itr).first, (*itr).second.first); + } else { + transformation.transform((*itr).second.first, (*itr).first); + } + (*itr).second.second *= sign; + } + if(dir1 != EAST || dir2 != NORTH) + unsorted_ = true; //some mirroring or rotation must have happened + return *this; + } + + // scale set + polygon_90_set_data& scale_up(typename coordinate_traits<coordinate_type>::unsigned_area_type factor) { + for(typename std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::iterator + itr = data_.begin(); itr != data_.end(); ++itr) { + (*itr).first *= (coordinate_type)factor; + (*itr).second.first *= (coordinate_type)factor; + } + return *this; + } + polygon_90_set_data& scale_down(typename coordinate_traits<coordinate_type>::unsigned_area_type factor) { + typedef typename coordinate_traits<coordinate_type>::coordinate_distance dt; + for(typename std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::iterator + itr = data_.begin(); itr != data_.end(); ++itr) { + (*itr).first = scaling_policy<coordinate_type>::round((dt)((*itr).first) / (dt)factor); + (*itr).second.first = scaling_policy<coordinate_type>::round((dt)((*itr).second.first) / (dt)factor); + } + unsorted_ = true; //scaling down can make coordinates equal that were not previously equal + return *this; + } + template <typename scaling_type> + polygon_90_set_data& scale(const anisotropic_scale_factor<scaling_type>& scaling) { + for(typename std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::iterator + itr = data_.begin(); itr != data_.end(); ++itr) { + if(orient_ == orientation_2d(VERTICAL)) { + scaling.scale((*itr).first, (*itr).second.first); + } else { + scaling.scale((*itr).second.first, (*itr).first); + } + } + unsorted_ = true; + return *this; + } + template <typename scaling_type> + polygon_90_set_data& scale_with(const scaling_type& scaling) { + for(typename std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::iterator + itr = data_.begin(); itr != data_.end(); ++itr) { + if(orient_ == orientation_2d(VERTICAL)) { + scaling.scale((*itr).first, (*itr).second.first); + } else { + scaling.scale((*itr).second.first, (*itr).first); + } + } + unsorted_ = true; + return *this; + } + polygon_90_set_data& scale(double factor) { + typedef typename coordinate_traits<coordinate_type>::coordinate_distance dt; + for(typename std::vector<std::pair<coordinate_type, std::pair<coordinate_type, int> > >::iterator + itr = data_.begin(); itr != data_.end(); ++itr) { + (*itr).first = scaling_policy<coordinate_type>::round((dt)((*itr).first) * (dt)factor); + (*itr).second.first = scaling_policy<coordinate_type>::round((dt)((*itr).second.first) * (dt)factor); + } + unsorted_ = true; //scaling make coordinates equal that were not previously equal + return *this; + } + + polygon_90_set_data& self_xor() { + sort(); + if(dirty_) { //if it is clean it is a no-op + boolean_op::default_arg_workaround<boolean_op::UnaryCount>::applyBooleanOr(data_); + dirty_ = false; + } + return *this; + } + + polygon_90_set_data& self_intersect() { + sort(); + if(dirty_) { //if it is clean it is a no-op + interval_data<coordinate_type> ivl((std::numeric_limits<coordinate_type>::min)(), (std::numeric_limits<coordinate_type>::max)()); + rectangle_data<coordinate_type> rect(ivl, ivl); + insert(rect, true); + clean(); + } + return *this; + } + + inline polygon_90_set_data& interact(const polygon_90_set_data& that) { + typedef coordinate_type Unit; + if(that.dirty_) that.clean(); + typename touch_90_operation<Unit>::TouchSetData tsd; + touch_90_operation<Unit>::populateTouchSetData(tsd, that.data_, 0); + std::vector<polygon_90_data<Unit> > polys; + get(polys); + std::vector<std::set<int> > graph(polys.size()+1, std::set<int>()); + for(std::size_t i = 0; i < polys.size(); ++i){ + polygon_90_set_data<Unit> psTmp(that.orient_); + psTmp.insert(polys[i]); + psTmp.clean(); + touch_90_operation<Unit>::populateTouchSetData(tsd, psTmp.data_, i+1); + } + touch_90_operation<Unit>::performTouch(graph, tsd); + clear(); + for(std::set<int>::iterator itr = graph[0].begin(); itr != graph[0].end(); ++itr){ + insert(polys[(*itr)-1]); + } + dirty_ = false; + return *this; + } + + + template <class T2, typename iterator_type_1, typename iterator_type_2> + void applyBooleanBinaryOp(iterator_type_1 itr1, iterator_type_1 itr1_end, + iterator_type_2 itr2, iterator_type_2 itr2_end, + T2 defaultCount) { + data_.clear(); + boolean_op::applyBooleanBinaryOp(data_, itr1, itr1_end, itr2, itr2_end, defaultCount); + } + + private: + orientation_2d orient_; + mutable value_type data_; + mutable bool dirty_; + mutable bool unsorted_; + + private: + //functions + template <typename output_container> + void get_dispatch(output_container& output, rectangle_concept ) const { + clean(); + form_rectangles(output, data_.begin(), data_.end(), orient_, rectangle_concept()); + } + template <typename output_container> + void get_dispatch(output_container& output, polygon_90_concept tag) const { + get_fracture(output, true, tag); + } + template <typename output_container> + void get_dispatch(output_container& output, polygon_90_with_holes_concept tag) const { + get_fracture(output, false, tag); + } + template <typename output_container> + void get_dispatch(output_container& output, polygon_45_concept tag) const { + get_fracture(output, true, tag); + } + template <typename output_container> + void get_dispatch(output_container& output, polygon_45_with_holes_concept tag) const { + get_fracture(output, false, tag); + } + template <typename output_container> + void get_dispatch(output_container& output, polygon_concept tag) const { + get_fracture(output, true, tag); + } + template <typename output_container> + void get_dispatch(output_container& output, polygon_with_holes_concept tag) const { + get_fracture(output, false, tag); + } + template <typename output_container, typename concept_type> + void get_fracture(output_container& container, bool fracture_holes, concept_type tag) const { + clean(); + ::boost::polygon::get_polygons(container, data_.begin(), data_.end(), orient_, fracture_holes, tag); + } + }; + + template <typename coordinate_type> + polygon_90_set_data<coordinate_type>& + polygon_90_set_data<coordinate_type>::resize(coordinate_type west, + coordinate_type east, + coordinate_type south, + coordinate_type north) { + move(-west, -south); + coordinate_type e_total = west + east; + coordinate_type n_total = south + north; + if((e_total < 0) ^ (n_total < 0)) { + //different signs + if(e_total < 0) { + shrink(0, -e_total, 0, 0); + if(n_total != 0) + return bloat(0, 0, 0, n_total); + else + return (*this); + } else { + shrink(0, 0, 0, -n_total); //shrink first + if(e_total != 0) + return bloat(0, e_total, 0, 0); + else + return (*this); + } + } else { + if(e_total < 0) { + return shrink(0, -e_total, 0, -n_total); + } + return bloat(0, e_total, 0, n_total); + } + } + + template <typename coordinate_type, typename property_type> + class property_merge_90 { + private: + std::vector<std::pair<property_merge_point<coordinate_type>, std::pair<property_type, int> > > pmd_; + public: + inline property_merge_90() : pmd_() {} + inline property_merge_90(const property_merge_90& that) : pmd_(that.pmd_) {} + inline property_merge_90& operator=(const property_merge_90& that) { pmd_ = that.pmd_; return *this; } + inline void insert(const polygon_90_set_data<coordinate_type>& ps, const property_type& property) { + merge_scanline<coordinate_type, property_type, polygon_90_set_data<coordinate_type> >:: + populate_property_merge_data(pmd_, ps.begin(), ps.end(), property, ps.orient()); + } + template <class GeoObjT> + inline void insert(const GeoObjT& geoObj, const property_type& property) { + polygon_90_set_data<coordinate_type> ps; + ps.insert(geoObj); + insert(ps, property); + } + //merge properties of input geometries and store the resulting geometries of regions + //with unique sets of merged properties to polygons sets in a map keyed by sets of properties + // T = std::map<std::set<property_type>, polygon_90_set_data<coordiante_type> > or + // T = std::map<std::vector<property_type>, polygon_90_set_data<coordiante_type> > + template <typename ResultType> + inline void merge(ResultType& result) { + merge_scanline<coordinate_type, property_type, polygon_90_set_data<coordinate_type>, typename ResultType::key_type> ms; + ms.perform_merge(result, pmd_); + } + }; + + //ConnectivityExtraction computes the graph of connectivity between rectangle, polygon and + //polygon set graph nodes where an edge is created whenever the geometry in two nodes overlap + template <typename coordinate_type> + class connectivity_extraction_90 { + private: + typedef typename touch_90_operation<coordinate_type>::TouchSetData tsd; + tsd tsd_; + unsigned int nodeCount_; + public: + inline connectivity_extraction_90() : tsd_(), nodeCount_(0) {} + inline connectivity_extraction_90(const connectivity_extraction_90& that) : tsd_(that.tsd_), + nodeCount_(that.nodeCount_) {} + inline connectivity_extraction_90& operator=(const connectivity_extraction_90& that) { + tsd_ = that.tsd_; + nodeCount_ = that.nodeCount_; {} + return *this; + } + + //insert a polygon set graph node, the value returned is the id of the graph node + inline unsigned int insert(const polygon_90_set_data<coordinate_type>& ps) { + ps.clean(); + touch_90_operation<coordinate_type>::populateTouchSetData(tsd_, ps.begin(), ps.end(), nodeCount_); + return nodeCount_++; + } + template <class GeoObjT> + inline unsigned int insert(const GeoObjT& geoObj) { + polygon_90_set_data<coordinate_type> ps; + ps.insert(geoObj); + return insert(ps); + } + + //extract connectivity and store the edges in the graph + //graph must be indexable by graph node id and the indexed value must be a std::set of + //graph node id + template <class GraphT> + inline void extract(GraphT& graph) { + touch_90_operation<coordinate_type>::performTouch(graph, tsd_); + } + }; +} +} +#endif + diff --git a/boost/polygon/polygon_90_set_traits.hpp b/boost/polygon/polygon_90_set_traits.hpp new file mode 100644 index 0000000000..18e632973c --- /dev/null +++ b/boost/polygon/polygon_90_set_traits.hpp @@ -0,0 +1,362 @@ +/* + 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_POLYGON_90_SET_TRAITS_HPP +#define BOOST_POLYGON_POLYGON_90_SET_TRAITS_HPP +namespace boost { namespace polygon{ + + struct polygon_90_set_concept {}; + + template <typename T, typename T2> + struct traits_by_concept {}; + template <typename T> + struct traits_by_concept<T, coordinate_concept> { typedef coordinate_traits<T> type; }; + template <typename T> + struct traits_by_concept<T, interval_concept> { typedef interval_traits<T> type; }; + template <typename T> + struct traits_by_concept<T, point_concept> { typedef point_traits<T> type; }; + template <typename T> + struct traits_by_concept<T, point_3d_concept> { typedef point_3d_traits<T> type; }; + template <typename T> + struct traits_by_concept<T, rectangle_concept> { typedef rectangle_traits<T> type; }; + template <typename T> + struct traits_by_concept<T, polygon_90_concept> { typedef polygon_traits<T> type; }; + template <typename T> + struct traits_by_concept<T, polygon_90_with_holes_concept> { typedef polygon_traits<T> type; }; + template <typename T> + struct traits_by_concept<T, polygon_45_concept> { typedef polygon_traits<T> type; }; + template <typename T> + struct traits_by_concept<T, polygon_45_with_holes_concept> { typedef polygon_traits<T> type; }; + template <typename T> + struct traits_by_concept<T, polygon_concept> { typedef polygon_traits<T> type; }; + template <typename T> + struct traits_by_concept<T, polygon_with_holes_concept> { typedef polygon_traits<T> type; }; + + struct polygon_45_set_concept; + struct polygon_set_concept; + template <typename T> + struct polygon_90_set_traits; + template <typename T> + struct polygon_45_set_traits; + template <typename T> + struct polygon_set_traits; + template <typename T> + struct traits_by_concept<T, polygon_90_set_concept> { typedef polygon_90_set_traits<T> type; }; + template <typename T> + struct traits_by_concept<T, polygon_45_set_concept> { typedef polygon_45_set_traits<T> type; }; + template <typename T> + struct traits_by_concept<T, polygon_set_concept> { typedef polygon_set_traits<T> type; }; + + template <typename T, typename T2> + struct get_coordinate_type { + typedef typename traits_by_concept<T, T2>::type traits_type; + typedef typename traits_type::coordinate_type type; + }; + //want to prevent recursive template definition syntax errors, so duplicate get_coordinate_type + template <typename T, typename T2> + struct get_coordinate_type_2 { + typedef typename traits_by_concept<T, T2>::type traits_type; + typedef typename traits_type::coordinate_type type; + }; + template <typename T> + struct get_coordinate_type<T, undefined_concept> { + typedef typename get_coordinate_type_2<typename std::iterator_traits + <typename T::iterator>::value_type, + typename geometry_concept<typename std::iterator_traits + <typename T::iterator>::value_type>::type>::type type; }; + + template <typename T, typename T2> + struct get_iterator_type_2 { + typedef const T* type; + static type begin(const T& t) { return &t; } + static type end(const T& t) { const T* tp = &t; ++tp; return tp; } + }; + template <typename T> + struct get_iterator_type { + typedef get_iterator_type_2<T, typename geometry_concept<T>::type> indirect_type; + typedef typename indirect_type::type type; + static type begin(const T& t) { return indirect_type::begin(t); } + static type end(const T& t) { return indirect_type::end(t); } + }; + template <typename T> + struct get_iterator_type_2<T, undefined_concept> { + typedef typename T::const_iterator type; + static type begin(const T& t) { return t.begin(); } + static type end(const T& t) { return t.end(); } + }; + +// //helpers for allowing polygon 45 and containers of polygon 45 to behave interchangably in polygon_45_set_traits +// template <typename T, typename T2> +// struct get_coordinate_type_45 {}; +// template <typename T, typename T2> +// struct get_coordinate_type_2_45 {}; +// template <typename T> +// struct get_coordinate_type_45<T, void> { +// typedef typename get_coordinate_type_2_45< typename T::value_type, typename geometry_concept<typename T::value_type>::type >::type type; }; +// template <typename T> +// struct get_coordinate_type_45<T, polygon_45_concept> { typedef typename polygon_traits<T>::coordinate_type type; }; +// template <typename T> +// struct get_coordinate_type_45<T, polygon_45_with_holes_concept> { typedef typename polygon_traits<T>::coordinate_type type; }; +// template <typename T> +// struct get_coordinate_type_2_45<T, polygon_45_concept> { typedef typename polygon_traits<T>::coordinate_type type; }; +// template <typename T> +// struct get_coordinate_type_2_45<T, polygon_45_with_holes_concept> { typedef typename polygon_traits<T>::coordinate_type type; }; +// template <typename T, typename T2> +// struct get_iterator_type_45 {}; +// template <typename T> +// struct get_iterator_type_45<T, void> { +// typedef typename T::const_iterator type; +// static type begin(const T& t) { return t.begin(); } +// static type end(const T& t) { return t.end(); } +// }; +// template <typename T> +// struct get_iterator_type_45<T, polygon_45_concept> { +// typedef const T* type; +// static type begin(const T& t) { return &t; } +// static type end(const T& t) { const T* tp = &t; ++tp; return tp; } +// }; +// template <typename T> +// struct get_iterator_type_45<T, polygon_45_with_holes_concept> { +// typedef const T* type; +// static type begin(const T& t) { return &t; } +// static type end(const T& t) { const T* tp = &t; ++tp; return tp; } +// }; +// template <typename T> +// struct get_iterator_type_45<T, polygon_90_set_concept> { +// typedef const T* type; +// static type begin(const T& t) { return &t; } +// static type end(const T& t) { const T* tp = &t; ++tp; return tp; } +// }; + + template <typename T> + struct polygon_90_set_traits { + typedef typename get_coordinate_type<T, typename geometry_concept<T>::type >::type coordinate_type; + typedef get_iterator_type<T> indirection_type; + typedef typename get_iterator_type<T>::type iterator_type; + typedef T operator_arg_type; + + static inline iterator_type begin(const T& polygon_set) { + return indirection_type::begin(polygon_set); + } + + static inline iterator_type end(const T& polygon_set) { + return indirection_type::end(polygon_set); + } + + static inline orientation_2d orient(const T&) { return HORIZONTAL; } + + static inline bool clean(const T&) { return false; } + + static inline bool sorted(const T&) { return false; } + }; + + template <typename T> + struct is_manhattan_polygonal_concept { typedef gtl_no type; }; + template <> + struct is_manhattan_polygonal_concept<rectangle_concept> { typedef gtl_yes type; }; + template <> + struct is_manhattan_polygonal_concept<polygon_90_concept> { typedef gtl_yes type; }; + template <> + struct is_manhattan_polygonal_concept<polygon_90_with_holes_concept> { typedef gtl_yes type; }; + template <> + struct is_manhattan_polygonal_concept<polygon_90_set_concept> { typedef gtl_yes type; }; + + template <typename T> + struct is_polygon_90_set_type { + typedef typename is_manhattan_polygonal_concept<typename geometry_concept<T>::type>::type type; + }; + template <typename T> + struct is_polygon_90_set_type<std::list<T> > { + typedef typename gtl_or< + typename is_manhattan_polygonal_concept<typename geometry_concept<std::list<T> >::type>::type, + typename is_manhattan_polygonal_concept<typename geometry_concept<typename std::list<T>::value_type>::type>::type>::type type; + }; + template <typename T> + struct is_polygon_90_set_type<std::vector<T> > { + typedef typename gtl_or< + typename is_manhattan_polygonal_concept<typename geometry_concept<std::vector<T> >::type>::type, + typename is_manhattan_polygonal_concept<typename geometry_concept<typename std::vector<T>::value_type>::type>::type>::type type; + }; + + template <typename T> + struct is_mutable_polygon_90_set_type { + typedef typename gtl_same_type<polygon_90_set_concept, typename geometry_concept<T>::type>::type type; + }; + template <typename T> + struct is_mutable_polygon_90_set_type<std::list<T> > { + typedef typename gtl_or< + typename gtl_same_type<polygon_90_set_concept, typename geometry_concept<std::list<T> >::type>::type, + typename is_manhattan_polygonal_concept<typename geometry_concept<typename std::list<T>::value_type>::type>::type>::type type; + }; + template <typename T> + struct is_mutable_polygon_90_set_type<std::vector<T> > { + typedef typename gtl_or< + typename gtl_same_type<polygon_90_set_concept, typename geometry_concept<std::vector<T> >::type>::type, + typename is_manhattan_polygonal_concept<typename geometry_concept<typename std::vector<T>::value_type>::type>::type>::type type; + }; + +// //specialization for rectangle, polygon_90 and polygon_90_with_holes types +// template <typename T> +// struct polygon_90_set_traits +// typedef typename geometry_concept<T>::type concept_type; +// typedef typename get_coordinate_type<T, concept_type>::type coordinate_type; +// typedef iterator_geometry_to_set<concept_type, T> iterator_type; +// typedef T operator_arg_type; + +// static inline iterator_type begin(const T& polygon_set) { +// return iterator_geometry_to_set<concept_type, T>(polygon_set, LOW, HORIZONTAL); +// } + +// static inline iterator_type end(const T& polygon_set) { +// return iterator_geometry_to_set<concept_type, T>(polygon_set, HIGH, HORIZONTAL); +// } + +// static inline orientation_2d orient(const T& polygon_set) { return HORIZONTAL; } + +// static inline bool clean(const T& polygon_set) { return false; } + +// static inline bool sorted(const T& polygon_set) { return false; } + +// }; + +// //specialization for containers of recangle, polygon_90, polygon_90_with_holes +// template <typename T> +// struct polygon_90_set_traits<T, typename is_manhattan_polygonal_concept<typename std::iterator_traits<typename T::iterator>::value_type>::type> { +// typedef typename std::iterator_traits<typename T::iterator>::value_type geometry_type; +// typedef typename geometry_concept<geometry_type>::type concept_type; +// typedef typename get_coordinate_type<geometry_type, concept_type>::type coordinate_type; +// typedef iterator_geometry_range_to_set<concept_type, typename T::const_iterator> iterator_type; +// typedef T operator_arg_type; + +// static inline iterator_type begin(const T& polygon_set) { +// return iterator_type(polygon_set.begin(), HORIZONTAL); +// } + +// static inline iterator_type end(const T& polygon_set) { +// return iterator_type(polygon_set.end(), HORIZONTAL); +// } + +// static inline orientation_2d orient(const T& polygon_set) { return HORIZONTAL; } + +// static inline bool clean(const T& polygon_set) { return false; } + +// static inline bool sorted(const T& polygon_set) { return false; } + +// }; + + //get dispatch functions + template <typename output_container_type, typename pst> + void get_90_dispatch(output_container_type& output, const pst& ps, + orientation_2d orient, rectangle_concept ) { + form_rectangles(output, ps.begin(), ps.end(), orient, rectangle_concept()); + } + + template <typename output_container_type, typename pst> + void get_90_dispatch(output_container_type& output, const pst& ps, + orientation_2d orient, polygon_90_concept tag) { + get_polygons(output, ps.begin(), ps.end(), orient, true, tag); + } + + template <typename output_container_type, typename pst> + void get_90_dispatch(output_container_type& output, const pst& ps, + orientation_2d orient, polygon_90_with_holes_concept tag) { + get_polygons(output, ps.begin(), ps.end(), orient, false, tag); + } + + //by default works with containers of rectangle, polygon or polygon with holes + //must be specialized to work with anything else + template <typename T> + struct polygon_90_set_mutable_traits {}; + template <typename T> + struct polygon_90_set_mutable_traits<std::list<T> > { + typedef typename geometry_concept<T>::type concept_type; + template <typename input_iterator_type> + static inline void set(std::list<T>& polygon_set, input_iterator_type input_begin, input_iterator_type input_end, orientation_2d orient) { + polygon_set.clear(); + polygon_90_set_data<typename polygon_90_set_traits<std::list<T> >::coordinate_type> ps(orient); + ps.insert(input_begin, input_end, orient); + ps.clean(); + get_90_dispatch(polygon_set, ps, orient, concept_type()); + } + }; + template <typename T> + struct polygon_90_set_mutable_traits<std::vector<T> > { + typedef typename geometry_concept<T>::type concept_type; + template <typename input_iterator_type> + static inline void set(std::vector<T>& polygon_set, input_iterator_type input_begin, input_iterator_type input_end, orientation_2d orient) { + polygon_set.clear(); + polygon_90_set_data<typename polygon_90_set_traits<std::list<T> >::coordinate_type> ps(orient); + ps.insert(input_begin, input_end, orient); + ps.clean(); + get_90_dispatch(polygon_set, ps, orient, concept_type()); + } + }; + + template <typename T> + struct polygon_90_set_mutable_traits<polygon_90_set_data<T> > { + + template <typename input_iterator_type> + static inline void set(polygon_90_set_data<T>& polygon_set, + input_iterator_type input_begin, input_iterator_type input_end, + orientation_2d orient) { + polygon_set.clear(); + polygon_set.insert(input_begin, input_end, orient); + } + + }; + + template <typename T> + struct polygon_90_set_traits<polygon_90_set_data<T> > { + typedef typename polygon_90_set_data<T>::coordinate_type coordinate_type; + typedef typename polygon_90_set_data<T>::iterator_type iterator_type; + typedef typename polygon_90_set_data<T>::operator_arg_type operator_arg_type; + + static inline iterator_type begin(const polygon_90_set_data<T>& polygon_set) { + return polygon_set.begin(); + } + + static inline iterator_type end(const polygon_90_set_data<T>& polygon_set) { + return polygon_set.end(); + } + + static inline orientation_2d orient(const polygon_90_set_data<T>& polygon_set) { return polygon_set.orient(); } + + static inline bool clean(const polygon_90_set_data<T>& polygon_set) { polygon_set.clean(); return true; } + + static inline bool sorted(const polygon_90_set_data<T>& polygon_set) { polygon_set.sort(); return true; } + + }; + + template <typename T> + struct is_polygon_90_set_concept { }; + template <> + struct is_polygon_90_set_concept<polygon_90_set_concept> { typedef gtl_yes type; }; + template <> + struct is_polygon_90_set_concept<rectangle_concept> { typedef gtl_yes type; }; + template <> + struct is_polygon_90_set_concept<polygon_90_concept> { typedef gtl_yes type; }; + template <> + struct is_polygon_90_set_concept<polygon_90_with_holes_concept> { typedef gtl_yes type; }; + + template <typename T> + struct is_mutable_polygon_90_set_concept { typedef gtl_no type; }; + template <> + struct is_mutable_polygon_90_set_concept<polygon_90_set_concept> { typedef gtl_yes type; }; + + template <typename T> + struct geometry_concept<polygon_90_set_data<T> > { typedef polygon_90_set_concept type; }; + + //template <typename T> + //typename enable_if<typename is_polygon_90_set_type<T>::type, void>::type + //print_is_polygon_90_set_concept(const T& t) { std::cout << "is polygon 90 set concept\n"; } + //template <typename T> + //typename enable_if<typename is_mutable_polygon_90_set_type<T>::type, void>::type + //print_is_mutable_polygon_90_set_concept(const T& t) { std::cout << "is mutable polygon 90 set concept\n"; } +} +} +#endif + diff --git a/boost/polygon/polygon_90_with_holes_data.hpp b/boost/polygon/polygon_90_with_holes_data.hpp new file mode 100644 index 0000000000..2fb6cdb9f2 --- /dev/null +++ b/boost/polygon/polygon_90_with_holes_data.hpp @@ -0,0 +1,116 @@ +/* + 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_POLYGON_90_WITH_HOLES_DATA_HPP +#define BOOST_POLYGON_POLYGON_90_WITH_HOLES_DATA_HPP +namespace boost { namespace polygon{ +#include "isotropy.hpp" +#include "polygon_90_data.hpp" +struct polygon_90_with_holes_concept; +template <typename T> +class polygon_90_with_holes_data { +public: + typedef polygon_90_with_holes_concept geometry_type; + typedef T coordinate_type; + typedef typename polygon_90_data<T>::iterator_type iterator_type; + typedef typename polygon_90_data<T>::compact_iterator_type compact_iterator_type; + typedef typename std::list<polygon_90_data<coordinate_type> >::const_iterator iterator_holes_type; + typedef polygon_90_data<coordinate_type> hole_type; + typedef typename coordinate_traits<T>::area_type area_type; + typedef point_data<T> point_type; + + // default constructor of point does not initialize x and y + inline polygon_90_with_holes_data() : self_(), holes_() {} //do nothing default constructor + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template<class iT> + inline polygon_90_with_holes_data& set(iT input_begin, iT input_end) { + self_.set(input_begin, input_end); + return *this; + } + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template<class iT> + inline polygon_90_with_holes_data& set_compact(iT input_begin, iT input_end) { + self_.set_compact(input_begin, input_end); + return *this; + } + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template<class iT> + inline polygon_90_with_holes_data& set_holes(iT input_begin, iT input_end) { + holes_.clear(); //just in case there was some old data there + for( ; input_begin != input_end; ++ input_begin) { + holes_.push_back(hole_type()); + holes_.back().set_compact((*input_begin).begin_compact(), (*input_begin).end_compact()); + } + return *this; + } + + // copy constructor (since we have dynamic memory) + inline polygon_90_with_holes_data(const polygon_90_with_holes_data& that) : self_(that.self_), + holes_(that.holes_) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline polygon_90_with_holes_data& operator=(const polygon_90_with_holes_data& that) { + self_ = that.self_; + holes_ = that.holes_; + return *this; + } + + template <typename T2> + inline polygon_90_with_holes_data& operator=(const T2& rvalue); + + // get begin iterator, returns a pointer to a const coordinate_type + inline const iterator_type begin() const { + return self_.begin(); + } + + // get end iterator, returns a pointer to a const coordinate_type + inline const iterator_type end() const { + return self_.end(); + } + + // get begin iterator, returns a pointer to a const coordinate_type + inline const compact_iterator_type begin_compact() const { + return self_.begin_compact(); + } + + // get end iterator, returns a pointer to a const coordinate_type + inline const compact_iterator_type end_compact() const { + return self_.end_compact(); + } + + inline std::size_t size() const { + return self_.size(); + } + + // get begin iterator, returns a pointer to a const polygon + inline const iterator_holes_type begin_holes() const { + return holes_.begin(); + } + + // get end iterator, returns a pointer to a const polygon + inline const iterator_holes_type end_holes() const { + return holes_.end(); + } + + inline std::size_t size_holes() const { + return holes_.size(); + } + +private: + polygon_90_data<coordinate_type> self_; + std::list<hole_type> holes_; +}; +} +} +#endif + diff --git a/boost/polygon/polygon_data.hpp b/boost/polygon/polygon_data.hpp new file mode 100644 index 0000000000..cd3b672299 --- /dev/null +++ b/boost/polygon/polygon_data.hpp @@ -0,0 +1,70 @@ +/* + 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_POLYGON_DATA_HPP +#define BOOST_POLYGON_POLYGON_DATA_HPP +namespace boost { namespace polygon{ +struct polygon_concept; +template <typename T> +class polygon_data { +public: + typedef polygon_concept geometry_type; + typedef T coordinate_type; + typedef typename std::vector<point_data<coordinate_type> >::const_iterator iterator_type; + typedef typename coordinate_traits<T>::coordinate_distance area_type; + typedef point_data<T> point_type; + + inline polygon_data() : coords_() {} //do nothing default constructor + + template<class iT> + inline polygon_data(iT input_begin, iT input_end) : coords_(input_begin, input_end) {} + + template<class iT> + inline polygon_data& set(iT input_begin, iT input_end) { + coords_.clear(); //just in case there was some old data there + coords_.insert(coords_.end(), input_begin, input_end); + return *this; + } + + // copy constructor (since we have dynamic memory) + inline polygon_data(const polygon_data& that) : coords_(that.coords_) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline polygon_data& operator=(const polygon_data& that) { + coords_ = that.coords_; + return *this; + } + + template <typename T2> + inline polygon_data& operator=(const T2& rvalue); + + inline bool operator==(const polygon_data& that) const { + if(coords_.size() != that.coords_.size()) return false; + for(std::size_t i = 0; i < coords_.size(); ++i) { + if(coords_[i] != that.coords_[i]) return false; + } + return true; + } + + inline bool operator!=(const polygon_data& that) const { return !((*this) == that); } + + // get begin iterator, returns a pointer to a const Unit + inline iterator_type begin() const { return coords_.begin(); } + + // get end iterator, returns a pointer to a const Unit + inline iterator_type end() const { return coords_.end(); } + + inline std::size_t size() const { return coords_.size(); } + +public: + std::vector<point_data<coordinate_type> > coords_; +}; + +} +} +#endif + diff --git a/boost/polygon/polygon_set_concept.hpp b/boost/polygon/polygon_set_concept.hpp new file mode 100644 index 0000000000..ecd2c70209 --- /dev/null +++ b/boost/polygon/polygon_set_concept.hpp @@ -0,0 +1,581 @@ +/* + 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_POLYGON_SET_CONCEPT_HPP +#define BOOST_POLYGON_POLYGON_SET_CONCEPT_HPP +#include "polygon_set_data.hpp" +#include "detail/polygon_simplify.hpp" +namespace boost { namespace polygon{ + + template <typename T, typename T2> + struct is_either_polygon_set_type { + typedef typename gtl_or<typename is_polygon_set_type<T>::type, typename is_polygon_set_type<T2>::type >::type type; + }; + + template <typename T> + struct is_any_polygon_set_type { + typedef typename gtl_or<typename is_polygon_45_or_90_set_type<T>::type, typename is_polygon_set_type<T>::type >::type type; + }; + + template <typename polygon_set_type> + typename enable_if< typename is_any_polygon_set_type<polygon_set_type>::type, + typename polygon_set_traits<polygon_set_type>::iterator_type>::type + begin_polygon_set_data(const polygon_set_type& polygon_set) { + return polygon_set_traits<polygon_set_type>::begin(polygon_set); + } + + template <typename polygon_set_type> + typename enable_if< typename is_any_polygon_set_type<polygon_set_type>::type, + typename polygon_set_traits<polygon_set_type>::iterator_type>::type + end_polygon_set_data(const polygon_set_type& polygon_set) { + return polygon_set_traits<polygon_set_type>::end(polygon_set); + } + + template <typename polygon_set_type> + typename enable_if< typename is_polygon_set_type<polygon_set_type>::type, + bool>::type + clean(const polygon_set_type& polygon_set) { + return polygon_set_traits<polygon_set_type>::clean(polygon_set); + } + + //assign + template <typename polygon_set_type_1, typename polygon_set_type_2> + typename enable_if< typename gtl_and< + typename is_mutable_polygon_set_type<polygon_set_type_1>::type, + typename is_any_polygon_set_type<polygon_set_type_2>::type>::type, + polygon_set_type_1>::type & + assign(polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { + if(clean(rvalue)) + polygon_set_mutable_traits<polygon_set_type_1>::set(lvalue, begin_polygon_set_data(rvalue), end_polygon_set_data(rvalue)); + else { + polygon_set_data<typename polygon_set_traits<polygon_set_type_2>::coordinate_type> ps; + ps.insert(begin_polygon_set_data(rvalue), end_polygon_set_data(rvalue)); + ps.clean(); + polygon_set_mutable_traits<polygon_set_type_1>::set(lvalue, ps.begin(), ps.end()); + } + return lvalue; + } + + //get trapezoids + template <typename output_container_type, typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, + void>::type + get_trapezoids(output_container_type& output, const polygon_set_type& polygon_set) { + polygon_set_data<typename polygon_set_traits<polygon_set_type>::coordinate_type> ps; + assign(ps, polygon_set); + ps.get_trapezoids(output); + } + + //get trapezoids + template <typename output_container_type, typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, + void>::type + get_trapezoids(output_container_type& output, const polygon_set_type& polygon_set, + orientation_2d orient) { + polygon_set_data<typename polygon_set_traits<polygon_set_type>::coordinate_type> ps; + assign(ps, polygon_set); + ps.get_trapezoids(output, orient); + } + + //equivalence + template <typename polygon_set_type_1, typename polygon_set_type_2> + typename enable_if< typename gtl_and_3 < + typename is_any_polygon_set_type<polygon_set_type_1>::type, + typename is_any_polygon_set_type<polygon_set_type_2>::type, + typename is_either_polygon_set_type<polygon_set_type_1, polygon_set_type_2>::type>::type, + bool>::type + equivalence(const polygon_set_type_1& lvalue, + const polygon_set_type_2& rvalue) { + polygon_set_data<typename polygon_set_traits<polygon_set_type_1>::coordinate_type> ps1; + assign(ps1, lvalue); + polygon_set_data<typename polygon_set_traits<polygon_set_type_2>::coordinate_type> ps2; + assign(ps2, rvalue); + return ps1 == ps2; + } + + //clear + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, + void>::type + clear(polygon_set_type& polygon_set) { + polygon_set_data<typename polygon_set_traits<polygon_set_type>::coordinate_type> ps; + assign(polygon_set, ps); + } + + //empty + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, + bool>::type + empty(const polygon_set_type& polygon_set) { + if(clean(polygon_set)) return begin_polygon_set_data(polygon_set) == end_polygon_set_data(polygon_set); + polygon_set_data<typename polygon_set_traits<polygon_set_type>::coordinate_type> ps; + assign(ps, polygon_set); + ps.clean(); + return ps.empty(); + } + + //extents + template <typename polygon_set_type, typename rectangle_type> + typename enable_if< typename gtl_and< + typename is_mutable_polygon_set_type<polygon_set_type>::type, + typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + bool>::type + extents(rectangle_type& extents_rectangle, + const polygon_set_type& polygon_set) { + clean(polygon_set); + polygon_set_data<typename polygon_set_traits<polygon_set_type>::coordinate_type> ps; + assign(ps, polygon_set); + return ps.extents(extents_rectangle); + } + + //area + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, + typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::area_type>::type + area(const polygon_set_type& polygon_set) { + typedef typename polygon_set_traits<polygon_set_type>::coordinate_type Unit; + typedef polygon_with_holes_data<Unit> p_type; + typedef typename coordinate_traits<Unit>::area_type area_type; + std::vector<p_type> polys; + assign(polys, polygon_set); + area_type retval = (area_type)0; + for(std::size_t i = 0; i < polys.size(); ++i) { + retval += area(polys[i]); + } + return retval; + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, + std::size_t>::type + simplify(polygon_set_type& polygon_set, typename coordinate_traits< + typename polygon_set_traits<polygon_set_type>::coordinate_type + >::coordinate_distance threshold) { + typedef typename polygon_set_traits<polygon_set_type>::coordinate_type Unit; + typedef polygon_with_holes_data<Unit> p_type; + std::vector<p_type> polys; + assign(polys, polygon_set); + std::size_t retval = 0; + for(std::size_t i = 0; i < polys.size(); ++i) { + retval += detail::simplify_detail::simplify(polys[i].self_.coords_, + polys[i].self_.coords_, threshold); + for(typename std::list<polygon_data<Unit> >::iterator itrh = + polys[i].holes_.begin(); itrh != (polys[i].holes_.end()); ++itrh) { + retval += detail::simplify_detail::simplify((*itrh).coords_, + (*itrh).coords_, threshold); + } + } + assign(polygon_set, polys); + return retval; + } + + template <typename polygon_set_type, typename coord_type> + typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, + polygon_set_type>::type & + resize(polygon_set_type& polygon_set, coord_type resizing, bool corner_fill_arcs = false, int num_circle_segments = 0) { + typedef typename polygon_set_traits<polygon_set_type>::coordinate_type Unit; + clean(polygon_set); + polygon_set_data<Unit> ps; + assign(ps, polygon_set); + ps.resize(resizing, corner_fill_arcs,num_circle_segments); + assign(polygon_set, ps); + return polygon_set; + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, + polygon_set_type>::type & + bloat(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type bloating) { + return resize(polygon_set, bloating); + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, + polygon_set_type>::type & + shrink(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type shrinking) { + return resize(polygon_set, -(typename polygon_set_traits<polygon_set_type>::coordinate_type)shrinking); + } + + //interact + template <typename polygon_set_type_1, typename polygon_set_type_2> + typename enable_if< typename gtl_and_3 < + typename is_any_polygon_set_type<polygon_set_type_1>::type, + typename is_any_polygon_set_type<polygon_set_type_2>::type, + typename is_either_polygon_set_type<polygon_set_type_1, polygon_set_type_2>::type>::type, + polygon_set_type_1>::type& + interact(polygon_set_type_1& polygon_set_1, const polygon_set_type_2& polygon_set_2) { + polygon_set_data<typename polygon_set_traits<polygon_set_type_1>::coordinate_type> ps1; + assign(ps1, polygon_set_1); + polygon_set_data<typename polygon_set_traits<polygon_set_type_2>::coordinate_type> ps2; + assign(ps2, polygon_set_2); + ps1.interact(ps2); + assign(polygon_set_1, ps1); + return polygon_set_1; + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, + polygon_set_type>::type & + scale_up(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type factor) { + typedef typename polygon_set_traits<polygon_set_type>::coordinate_type Unit; + clean(polygon_set); + polygon_set_data<Unit> ps; + assign(ps, polygon_set); + ps.scale_up(factor); + assign(polygon_set, ps); + return polygon_set; + } + + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, + polygon_set_type>::type & + scale_down(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type factor) { + typedef typename polygon_set_traits<polygon_set_type>::coordinate_type Unit; + clean(polygon_set); + polygon_set_data<Unit> ps; + assign(ps, polygon_set); + ps.scale_down(factor); + assign(polygon_set, ps); + return polygon_set; + } + + //transform + template <typename polygon_set_type, typename transformation_type> + typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, + polygon_set_type>::type & + transform(polygon_set_type& polygon_set, + const transformation_type& transformation) { + typedef typename polygon_set_traits<polygon_set_type>::coordinate_type Unit; + clean(polygon_set); + polygon_set_data<Unit> ps; + assign(ps, polygon_set); + ps.transform(transformation); + assign(polygon_set, ps); + return polygon_set; + } + + //keep + template <typename polygon_set_type> + typename enable_if< typename is_mutable_polygon_set_type<polygon_set_type>::type, + polygon_set_type>::type & + keep(polygon_set_type& polygon_set, + typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::area_type min_area, + typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::area_type max_area, + typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type min_width, + typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type max_width, + typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type min_height, + typename coordinate_traits<typename polygon_set_traits<polygon_set_type>::coordinate_type>::unsigned_area_type max_height) { + typedef typename polygon_set_traits<polygon_set_type>::coordinate_type Unit; + typedef typename coordinate_traits<Unit>::unsigned_area_type uat; + std::list<polygon_with_holes_data<Unit> > polys; + assign(polys, polygon_set); + typename std::list<polygon_with_holes_data<Unit> >::iterator itr_nxt; + for(typename std::list<polygon_with_holes_data<Unit> >::iterator itr = polys.begin(); itr != polys.end(); itr = itr_nxt){ + itr_nxt = itr; + ++itr_nxt; + rectangle_data<Unit> bbox; + extents(bbox, *itr); + uat pwidth = delta(bbox, HORIZONTAL); + if(pwidth > min_width && pwidth <= max_width){ + uat pheight = delta(bbox, VERTICAL); + if(pheight > min_height && pheight <= max_height){ + typename coordinate_traits<Unit>::area_type parea = area(*itr); + if(parea <= max_area && parea >= min_area) { + continue; + } + } + } + polys.erase(itr); + } + assign(polygon_set, polys); + return polygon_set; + } + + namespace operators { + + struct yes_ps_ob : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_4 < yes_ps_ob, typename is_any_polygon_set_type<geometry_type_1>::type, + typename is_any_polygon_set_type<geometry_type_2>::type, + typename is_either_polygon_set_type<geometry_type_1, geometry_type_2>::type>::type, + polygon_set_view<geometry_type_1, geometry_type_2, 0> >::type + operator|(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_set_view<geometry_type_1, geometry_type_2, 0> + (lvalue, rvalue); + } + + struct yes_ps_op : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_4 < yes_ps_op, + typename gtl_if<typename is_any_polygon_set_type<geometry_type_1>::type>::type, + typename gtl_if<typename is_any_polygon_set_type<geometry_type_2>::type>::type, + typename gtl_if<typename is_either_polygon_set_type<geometry_type_1, geometry_type_2>::type>::type> + ::type, polygon_set_view<geometry_type_1, geometry_type_2, 0> >::type + operator+(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_set_view<geometry_type_1, geometry_type_2, 0> + (lvalue, rvalue); + } + + struct yes_ps_os : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_4 < yes_ps_os, + typename is_any_polygon_set_type<geometry_type_1>::type, + typename is_any_polygon_set_type<geometry_type_2>::type, + typename is_either_polygon_set_type<geometry_type_1, geometry_type_2>::type>::type, + polygon_set_view<geometry_type_1, geometry_type_2, 1> >::type + operator*(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_set_view<geometry_type_1, geometry_type_2, 1> + (lvalue, rvalue); + } + + struct yes_ps_oa : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_4 < yes_ps_oa, + typename is_any_polygon_set_type<geometry_type_1>::type, + typename is_any_polygon_set_type<geometry_type_2>::type, + typename is_either_polygon_set_type<geometry_type_1, geometry_type_2>::type>::type, + polygon_set_view<geometry_type_1, geometry_type_2, 1> >::type + operator&(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_set_view<geometry_type_1, geometry_type_2, 1> + (lvalue, rvalue); + } + + struct yes_ps_ox : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_4 < yes_ps_ox, + typename is_any_polygon_set_type<geometry_type_1>::type, + typename is_any_polygon_set_type<geometry_type_2>::type, + typename is_either_polygon_set_type<geometry_type_1, geometry_type_2>::type>::type, + polygon_set_view<geometry_type_1, geometry_type_2, 2> >::type + operator^(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_set_view<geometry_type_1, geometry_type_2, 2> + (lvalue, rvalue); + } + + struct yes_ps_om : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_4 < yes_ps_om, + typename gtl_if<typename is_any_polygon_set_type<geometry_type_1>::type>::type, + typename gtl_if<typename is_any_polygon_set_type<geometry_type_2>::type>::type, + typename gtl_if<typename is_either_polygon_set_type<geometry_type_1, geometry_type_2>::type>::type> + ::type, polygon_set_view<geometry_type_1, geometry_type_2, 3> >::type + operator-(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_set_view<geometry_type_1, geometry_type_2, 3> + (lvalue, rvalue); + } + + struct yes_ps_ope : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_4< yes_ps_ope, gtl_yes, typename is_mutable_polygon_set_type<geometry_type_1>::type, + typename is_any_polygon_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator+=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op<geometry_type_1, geometry_type_2, 0>(lvalue, rvalue); + } + + struct yes_ps_obe : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3< yes_ps_obe, typename is_mutable_polygon_set_type<geometry_type_1>::type, + typename is_any_polygon_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator|=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op<geometry_type_1, geometry_type_2, 0>(lvalue, rvalue); + } + + struct yes_ps_ose : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3< yes_ps_ose, typename is_mutable_polygon_set_type<geometry_type_1>::type, + typename is_any_polygon_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator*=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op<geometry_type_1, geometry_type_2, 1>(lvalue, rvalue); + } + + struct yes_ps_oae : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< + typename gtl_and_3< yes_ps_oae, typename is_mutable_polygon_set_type<geometry_type_1>::type, + typename is_any_polygon_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator&=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op<geometry_type_1, geometry_type_2, 1>(lvalue, rvalue); + } + + struct yes_ps_oxe : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< typename gtl_and_3< yes_ps_oxe, typename is_mutable_polygon_set_type<geometry_type_1>::type, + typename is_any_polygon_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator^=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op<geometry_type_1, geometry_type_2, 2>(lvalue, rvalue); + } + + struct yes_ps_ome : gtl_yes {}; + + template <typename geometry_type_1, typename geometry_type_2> + typename enable_if< + typename gtl_and_3< yes_ps_ome, typename is_mutable_polygon_set_type<geometry_type_1>::type, + typename is_any_polygon_set_type<geometry_type_2>::type>::type, + geometry_type_1>::type & + operator-=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op<geometry_type_1, geometry_type_2, 3>(lvalue, rvalue); + } + + // TODO: Dafna, test these four resizing operators + struct y_ps_rpe : gtl_yes {}; + + template <typename geometry_type_1, typename coordinate_type_1> + typename enable_if< typename gtl_and_3< y_ps_rpe, typename is_mutable_polygon_set_type<geometry_type_1>::type, + typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, + coordinate_concept>::type>::type, + geometry_type_1>::type & + operator+=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { + return resize(lvalue, rvalue); + } + + struct y_ps_rme : gtl_yes {}; + + template <typename geometry_type_1, typename coordinate_type_1> + typename enable_if< typename gtl_and_3<y_ps_rme, typename gtl_if<typename is_mutable_polygon_set_type<geometry_type_1>::type>::type, + typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, + coordinate_concept>::type>::type, + geometry_type_1>::type & + operator-=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { + return resize(lvalue, -rvalue); + } + + struct y_ps_rp : gtl_yes {}; + + template <typename geometry_type_1, typename coordinate_type_1> + typename enable_if< typename gtl_and_3<y_ps_rp, typename gtl_if<typename is_mutable_polygon_set_type<geometry_type_1>::type>::type, + typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, + coordinate_concept>::type> + ::type, geometry_type_1>::type + operator+(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { + geometry_type_1 retval(lvalue); + retval += rvalue; + return retval; + } + + struct y_ps_rm : gtl_yes {}; + + template <typename geometry_type_1, typename coordinate_type_1> + typename enable_if< typename gtl_and_3<y_ps_rm, typename gtl_if<typename is_mutable_polygon_set_type<geometry_type_1>::type>::type, + typename gtl_same_type<typename geometry_concept<coordinate_type_1>::type, + coordinate_concept>::type> + ::type, geometry_type_1>::type + operator-(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { + geometry_type_1 retval(lvalue); + retval -= rvalue; + return retval; + } + + + } //end operators namespace + + template <typename T> + struct view_of<polygon_45_set_concept, T> { + typedef typename get_coordinate_type<T, typename geometry_concept<T>::type >::type coordinate_type; + T* tp; + std::vector<polygon_45_with_holes_data<coordinate_type> > polys; + view_of(const T& obj) : tp(), polys() { + std::vector<polygon_with_holes_data<coordinate_type> > gpolys; + assign(gpolys, obj); + for(typename std::vector<polygon_with_holes_data<coordinate_type> >::iterator itr = gpolys.begin(); + itr != gpolys.end(); ++itr) { + polys.push_back(polygon_45_with_holes_data<coordinate_type>()); + assign(polys.back(), view_as<polygon_45_with_holes_concept>(*itr)); + } + } + view_of(T& obj) : tp(&obj), polys() { + std::vector<polygon_with_holes_data<coordinate_type> > gpolys; + assign(gpolys, obj); + for(typename std::vector<polygon_with_holes_data<coordinate_type> >::iterator itr = gpolys.begin(); + itr != gpolys.end(); ++itr) { + polys.push_back(polygon_45_with_holes_data<coordinate_type>()); + assign(polys.back(), view_as<polygon_45_with_holes_concept>(*itr)); + } + } + + typedef typename std::vector<polygon_45_with_holes_data<coordinate_type> >::const_iterator iterator_type; + typedef view_of operator_arg_type; + + inline iterator_type begin() const { + return polys.begin(); + } + + inline iterator_type end() const { + return polys.end(); + } + + inline orientation_2d orient() const { return HORIZONTAL; } + + inline bool clean() const { return false; } + + inline bool sorted() const { return false; } + + inline T& get() { return *tp; } + }; + + template <typename T> + struct polygon_45_set_traits<view_of<polygon_45_set_concept, T> > { + typedef typename view_of<polygon_45_set_concept, T>::coordinate_type coordinate_type; + typedef typename view_of<polygon_45_set_concept, T>::iterator_type iterator_type; + typedef view_of<polygon_45_set_concept, T> operator_arg_type; + + static inline iterator_type begin(const view_of<polygon_45_set_concept, T>& polygon_set) { + return polygon_set.begin(); + } + + static inline iterator_type end(const view_of<polygon_45_set_concept, T>& polygon_set) { + return polygon_set.end(); + } + + static inline orientation_2d orient(const view_of<polygon_45_set_concept, T>& polygon_set) { + return polygon_set.orient(); } + + static inline bool clean(const view_of<polygon_45_set_concept, T>& polygon_set) { + return polygon_set.clean(); } + + static inline bool sorted(const view_of<polygon_45_set_concept, T>& polygon_set) { + return polygon_set.sorted(); } + + }; + + template <typename T> + struct geometry_concept<view_of<polygon_45_set_concept, T> > { + typedef polygon_45_set_concept type; + }; + + template <typename T> + struct get_coordinate_type<view_of<polygon_45_set_concept, T>, polygon_45_set_concept> { + typedef typename view_of<polygon_45_set_concept, T>::coordinate_type type; + }; + template <typename T> + struct get_iterator_type_2<view_of<polygon_45_set_concept, T>, polygon_45_set_concept> { + typedef typename view_of<polygon_45_set_concept, T>::iterator_type type; + static type begin(const view_of<polygon_45_set_concept, T>& t) { return t.begin(); } + static type end(const view_of<polygon_45_set_concept, T>& t) { return t.end(); } + }; +} +} +#endif diff --git a/boost/polygon/polygon_set_data.hpp b/boost/polygon/polygon_set_data.hpp new file mode 100644 index 0000000000..bbddacf241 --- /dev/null +++ b/boost/polygon/polygon_set_data.hpp @@ -0,0 +1,1000 @@ +/* + 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_POLYGON_SET_DATA_HPP +#define BOOST_POLYGON_POLYGON_SET_DATA_HPP +#include "polygon_45_set_data.hpp" +#include "polygon_45_set_concept.hpp" +#include "polygon_traits.hpp" +#include "detail/polygon_arbitrary_formation.hpp" +#include <iostream> + +namespace boost { namespace polygon { + + + // utility function to round coordinate types down + // rounds down for both negative and positive numbers + // intended really for integer type T (does not make sense for float) + template <typename T> + static inline T round_down(double val) { + T rounded_val = (T)(val); + if(val < (double)rounded_val) + --rounded_val; + return rounded_val; + } + template <typename T> + static inline point_data<T> round_down(point_data<double> v) { + return point_data<T>(round_down<T>(v.x()),round_down<T>(v.y())); + } + + + + //foward declare view + template <typename ltype, typename rtype, int op_type> class polygon_set_view; + + template <typename T> + class polygon_set_data { + public: + typedef T coordinate_type; + typedef point_data<T> point_type; + typedef std::pair<point_type, point_type> edge_type; + typedef std::pair<edge_type, int> element_type; + typedef std::vector<element_type> value_type; + typedef typename value_type::const_iterator iterator_type; + typedef polygon_set_data operator_arg_type; + + // default constructor + inline polygon_set_data() : data_(), dirty_(false), unsorted_(false), is_45_(true) {} + + // constructor from an iterator pair over edge data + template <typename iT> + inline polygon_set_data(iT input_begin, iT input_end) : data_(), dirty_(false), unsorted_(false), is_45_(true) { + for( ; input_begin != input_end; ++input_begin) { insert(*input_begin); } + } + + // copy constructor + inline polygon_set_data(const polygon_set_data& that) : + data_(that.data_), dirty_(that.dirty_), unsorted_(that.unsorted_), is_45_(that.is_45_) {} + + // copy constructor + template <typename ltype, typename rtype, int op_type> + inline polygon_set_data(const polygon_set_view<ltype, rtype, op_type>& that); + + // destructor + inline ~polygon_set_data() {} + + // assignement operator + inline polygon_set_data& operator=(const polygon_set_data& that) { + if(this == &that) return *this; + data_ = that.data_; + dirty_ = that.dirty_; + unsorted_ = that.unsorted_; + is_45_ = that.is_45_; + return *this; + } + + template <typename ltype, typename rtype, int op_type> + inline polygon_set_data& operator=(const polygon_set_view<ltype, rtype, op_type>& geometry) { + (*this) = geometry.value(); + dirty_ = false; + unsorted_ = false; + return *this; + } + + template <typename geometry_object> + inline polygon_set_data& operator=(const geometry_object& geometry) { + data_.clear(); + insert(geometry); + return *this; + } + + + // insert iterator range + inline void insert(iterator_type input_begin, iterator_type input_end, bool is_hole = false) { + if(input_begin == input_end || (!data_.empty() && &(*input_begin) == &(*(data_.begin())))) return; + dirty_ = true; + unsorted_ = true; + while(input_begin != input_end) { + insert(*input_begin, is_hole); + ++input_begin; + } + } + + // insert iterator range + template <typename iT> + inline void insert(iT input_begin, iT input_end, bool is_hole = false) { + if(input_begin == input_end) return; + for(; input_begin != input_end; ++input_begin) { + insert(*input_begin, is_hole); + } + } + + template <typename geometry_type> + inline void insert(const geometry_type& geometry_object, bool is_hole = false) { + insert(geometry_object, is_hole, typename geometry_concept<geometry_type>::type()); + } + + template <typename polygon_type> + inline void insert(const polygon_type& polygon_object, bool is_hole, polygon_concept ) { + insert_vertex_sequence(begin_points(polygon_object), end_points(polygon_object), winding(polygon_object), is_hole); + } + + inline void insert(const polygon_set_data& ps, bool is_hole = false) { + insert(ps.data_.begin(), ps.data_.end(), is_hole); + } + + template <typename polygon_45_set_type> + inline void insert(const polygon_45_set_type& ps, bool is_hole, polygon_45_set_concept) { + std::vector<polygon_45_with_holes_data<typename polygon_45_set_traits<polygon_45_set_type>::coordinate_type> > polys; + assign(polys, ps); + insert(polys.begin(), polys.end(), is_hole); + } + + template <typename polygon_90_set_type> + inline void insert(const polygon_90_set_type& ps, bool is_hole, polygon_90_set_concept) { + std::vector<polygon_90_with_holes_data<typename polygon_90_set_traits<polygon_90_set_type>::coordinate_type> > polys; + assign(polys, ps); + insert(polys.begin(), polys.end(), is_hole); + } + + template <typename polygon_type> + inline void insert(const polygon_type& polygon_object, bool is_hole, polygon_45_concept ) { + insert(polygon_object, is_hole, polygon_concept()); } + + template <typename polygon_type> + inline void insert(const polygon_type& polygon_object, bool is_hole, polygon_90_concept ) { + insert(polygon_object, is_hole, polygon_concept()); } + + template <typename polygon_with_holes_type> + inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, + polygon_with_holes_concept ) { + insert(polygon_with_holes_object, is_hole, polygon_concept()); + for(typename polygon_with_holes_traits<polygon_with_holes_type>::iterator_holes_type itr = + begin_holes(polygon_with_holes_object); + itr != end_holes(polygon_with_holes_object); ++itr) { + insert(*itr, !is_hole, polygon_concept()); + } + } + + template <typename polygon_with_holes_type> + inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, + polygon_45_with_holes_concept ) { + insert(polygon_with_holes_object, is_hole, polygon_with_holes_concept()); } + + template <typename polygon_with_holes_type> + inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, + polygon_90_with_holes_concept ) { + insert(polygon_with_holes_object, is_hole, polygon_with_holes_concept()); } + + template <typename rectangle_type> + inline void insert(const rectangle_type& rectangle_object, bool is_hole, rectangle_concept ) { + polygon_90_data<coordinate_type> poly; + assign(poly, rectangle_object); + insert(poly, is_hole, polygon_concept()); + } + + inline void insert_clean(const element_type& edge, bool is_hole = false) { + if( ! scanline_base<coordinate_type>::is_45_degree(edge.first) && + ! scanline_base<coordinate_type>::is_horizontal(edge.first) && + ! scanline_base<coordinate_type>::is_vertical(edge.first) ) is_45_ = false; + data_.push_back(edge); + if(data_.back().first.second < data_.back().first.first) { + std::swap(data_.back().first.second, data_.back().first.first); + data_.back().second *= -1; + } + if(is_hole) + data_.back().second *= -1; + } + + inline void insert(const element_type& edge, bool is_hole = false) { + insert_clean(edge, is_hole); + dirty_ = true; + unsorted_ = true; + } + + template <class iT> + inline void insert_vertex_sequence(iT begin_vertex, iT end_vertex, direction_1d winding, bool is_hole) { + bool first_iteration = true; + point_type first_point; + point_type previous_point; + point_type current_point; + direction_1d winding_dir = winding; + int multiplier = winding_dir == COUNTERCLOCKWISE ? 1 : -1; + if(is_hole) multiplier *= -1; + for( ; begin_vertex != end_vertex; ++begin_vertex) { + assign(current_point, *begin_vertex); + if(first_iteration) { + first_iteration = false; + first_point = previous_point = current_point; + } else { + if(previous_point != current_point) { + element_type elem(edge_type(previous_point, current_point), + ( previous_point.get(HORIZONTAL) == current_point.get(HORIZONTAL) ? -1 : 1) * multiplier); + insert_clean(elem); + } + } + previous_point = current_point; + } + current_point = first_point; + if(!first_iteration) { + if(previous_point != current_point) { + element_type elem(edge_type(previous_point, current_point), + ( previous_point.get(HORIZONTAL) == current_point.get(HORIZONTAL) ? -1 : 1) * multiplier); + insert_clean(elem); + } + dirty_ = true; + unsorted_ = true; + } + } + + template <typename output_container> + inline void get(output_container& output) const { + get_dispatch(output, typename geometry_concept<typename output_container::value_type>::type()); + } + + // append to the container cT with polygons of three or four verticies + // slicing orientation is vertical + template <class cT> + void get_trapezoids(cT& container) const { + clean(); + trapezoid_arbitrary_formation<coordinate_type> pf; + typedef typename polygon_arbitrary_formation<coordinate_type>::vertex_half_edge vertex_half_edge; + std::vector<vertex_half_edge> data; + for(iterator_type itr = data_.begin(); itr != data_.end(); ++itr){ + data.push_back(vertex_half_edge((*itr).first.first, (*itr).first.second, (*itr).second)); + data.push_back(vertex_half_edge((*itr).first.second, (*itr).first.first, -1 * (*itr).second)); + } + gtlsort(data.begin(), data.end()); + pf.scan(container, data.begin(), data.end()); + //std::cout << "DONE FORMING POLYGONS\n"; + } + + // append to the container cT with polygons of three or four verticies + template <class cT> + void get_trapezoids(cT& container, orientation_2d slicing_orientation) const { + if(slicing_orientation == VERTICAL) { + get_trapezoids(container); + } else { + polygon_set_data<T> ps(*this); + ps.transform(axis_transformation(axis_transformation::SWAP_XY)); + cT result; + ps.get_trapezoids(result); + for(typename cT::iterator itr = result.begin(); itr != result.end(); ++itr) { + ::boost::polygon::transform(*itr, axis_transformation(axis_transformation::SWAP_XY)); + } + container.insert(container.end(), result.begin(), result.end()); + } + } + + // equivalence operator + inline bool operator==(const polygon_set_data& p) const { + clean(); + p.clean(); + return data_ == p.data_; + } + + // inequivalence operator + inline bool operator!=(const polygon_set_data& p) const { + return !((*this) == p); + } + + // get iterator to begin vertex data + inline iterator_type begin() const { + return data_.begin(); + } + + // get iterator to end vertex data + inline iterator_type end() const { + return data_.end(); + } + + const value_type& value() const { + return data_; + } + + // clear the contents of the polygon_set_data + inline void clear() { data_.clear(); dirty_ = unsorted_ = false; } + + // find out if Polygon set is empty + inline bool empty() const { return data_.empty(); } + + // get the Polygon set size in vertices + inline std::size_t size() const { clean(); return data_.size(); } + + // get the current Polygon set capacity in vertices + inline std::size_t capacity() const { return data_.capacity(); } + + // reserve size of polygon set in vertices + inline void reserve(std::size_t size) { return data_.reserve(size); } + + // find out if Polygon set is sorted + inline bool sorted() const { return !unsorted_; } + + // find out if Polygon set is clean + inline bool dirty() const { return dirty_; } + + void clean() const; + + void sort() const{ + if(unsorted_) { + gtlsort(data_.begin(), data_.end()); + unsorted_ = false; + } + } + + template <typename input_iterator_type> + void set(input_iterator_type input_begin, input_iterator_type input_end) { + clear(); + insert(input_begin, input_end); + dirty_ = true; + unsorted_ = true; + } + + void set(const value_type& value) { + data_ = value; + dirty_ = true; + unsorted_ = true; + } + + template <typename rectangle_type> + bool extents(rectangle_type& rect) { + clean(); + if(empty()) return false; + bool first_iteration = true; + for(iterator_type itr = begin(); + itr != end(); ++itr) { + rectangle_type edge_box; + set_points(edge_box, (*itr).first.first, (*itr).first.second); + if(first_iteration) + rect = edge_box; + else + encompass(rect, edge_box); + first_iteration = false; + } + return true; + } + + inline polygon_set_data& + resize(coordinate_type resizing, bool corner_fill_arc = false, unsigned int num_circle_segments=0); + + template <typename transform_type> + inline polygon_set_data& + transform(const transform_type& tr) { + std::vector<polygon_with_holes_data<T> > polys; + get(polys); + clear(); + for(std::size_t i = 0 ; i < polys.size(); ++i) { + ::boost::polygon::transform(polys[i], tr); + insert(polys[i]); + } + unsorted_ = true; + dirty_ = true; + return *this; + } + + inline polygon_set_data& + scale_up(typename coordinate_traits<coordinate_type>::unsigned_area_type factor) { + for(typename value_type::iterator itr = data_.begin(); itr != data_.end(); ++itr) { + ::boost::polygon::scale_up((*itr).first.first, factor); + ::boost::polygon::scale_up((*itr).first.second, factor); + } + return *this; + } + + inline polygon_set_data& + scale_down(typename coordinate_traits<coordinate_type>::unsigned_area_type factor) { + for(typename value_type::iterator itr = data_.begin(); itr != data_.end(); ++itr) { + ::boost::polygon::scale_down((*itr).first.first, factor); + ::boost::polygon::scale_down((*itr).first.second, factor); + } + unsorted_ = true; + dirty_ = true; + return *this; + } + + template <typename scaling_type> + inline polygon_set_data& scale(polygon_set_data& polygon_set, + const scaling_type& scaling) { + for(typename value_type::iterator itr = begin(); itr != end(); ++itr) { + ::boost::polygon::scale((*itr).first.first, scaling); + ::boost::polygon::scale((*itr).first.second, scaling); + } + unsorted_ = true; + dirty_ = true; + return *this; + } + + static inline void compute_offset_edge(point_data<long double>& pt1, point_data<long double>& pt2, + const point_data<long double>& prev_pt, + const point_data<long double>& current_pt, + long double distance, int multiplier) { + long double dx = current_pt.x() - prev_pt.x(); + long double dy = current_pt.y() - prev_pt.y(); + long double edge_length = std::sqrt(dx*dx + dy*dy); + long double dnx = dy; + long double dny = -dx; + dnx = dnx * (long double)distance / edge_length; + dny = dny * (long double)distance / edge_length; + pt1.x(prev_pt.x() + (long double)dnx * (long double)multiplier); + pt2.x(current_pt.x() + (long double)dnx * (long double)multiplier); + pt1.y(prev_pt.y() + (long double)dny * (long double)multiplier); + pt2.y(current_pt.y() + (long double)dny * (long double)multiplier); + } + + static inline void modify_pt(point_data<coordinate_type>& pt, const point_data<coordinate_type>& prev_pt, + const point_data<coordinate_type>& current_pt, const point_data<coordinate_type>& next_pt, + coordinate_type distance, coordinate_type multiplier) { + std::pair<point_data<long double>, point_data<long double> > he1, he2; + he1.first.x((long double)(prev_pt.x())); + he1.first.y((long double)(prev_pt.y())); + he1.second.x((long double)(current_pt.x())); + he1.second.y((long double)(current_pt.y())); + he2.first.x((long double)(current_pt.x())); + he2.first.y((long double)(current_pt.y())); + he2.second.x((long double)(next_pt.x())); + he2.second.y((long double)(next_pt.y())); + compute_offset_edge(he1.first, he1.second, prev_pt, current_pt, distance, multiplier); + compute_offset_edge(he2.first, he2.second, current_pt, next_pt, distance, multiplier); + typename scanline_base<long double>::compute_intersection_pack pack; + point_data<long double> rpt; + point_data<long double> bisectorpt((he1.second.x()+he2.first.x())/2, + (he1.second.y()+he2.first.y())/2); + point_data<long double> orig_pt((long double)pt.x(), (long double)pt.y()); + if(euclidean_distance(bisectorpt, orig_pt) < distance/2) { + if(!pack.compute_lazy_intersection(rpt, he1, he2, true, false)) { + rpt = he1.second; //colinear offset edges use shared point + } + } else { + if(!pack.compute_lazy_intersection(rpt, he1, std::pair<point_data<long double>, point_data<long double> >(orig_pt, bisectorpt), true, false)) { + rpt = he1.second; //colinear offset edges use shared point + } + } + pt.x((coordinate_type)(std::floor(rpt.x()+0.5))); + pt.y((coordinate_type)(std::floor(rpt.y()+0.5))); + } + + static void resize_poly_up(std::vector<point_data<coordinate_type> >& poly, coordinate_type distance, coordinate_type multiplier) { + point_data<coordinate_type> first_pt = poly[0]; + point_data<coordinate_type> second_pt = poly[1]; + point_data<coordinate_type> prev_pt = poly[0]; + point_data<coordinate_type> current_pt = poly[1]; + for(std::size_t i = 2; i < poly.size()-1; ++i) { + point_data<coordinate_type> next_pt = poly[i]; + modify_pt(poly[i-1], prev_pt, current_pt, next_pt, distance, multiplier); + prev_pt = current_pt; + current_pt = next_pt; + } + point_data<coordinate_type> next_pt = first_pt; + modify_pt(poly[poly.size()-2], prev_pt, current_pt, next_pt, distance, multiplier); + prev_pt = current_pt; + current_pt = next_pt; + next_pt = second_pt; + modify_pt(poly[0], prev_pt, current_pt, next_pt, distance, multiplier); + poly.back() = poly.front(); + } + static bool resize_poly_down(std::vector<point_data<coordinate_type> >& poly, coordinate_type distance, coordinate_type multiplier) { + std::vector<point_data<coordinate_type> > orig_poly(poly); + rectangle_data<coordinate_type> extents_rectangle; + set_points(extents_rectangle, poly[0], poly[0]); + point_data<coordinate_type> first_pt = poly[0]; + point_data<coordinate_type> second_pt = poly[1]; + point_data<coordinate_type> prev_pt = poly[0]; + point_data<coordinate_type> current_pt = poly[1]; + encompass(extents_rectangle, current_pt); + for(std::size_t i = 2; i < poly.size()-1; ++i) { + point_data<coordinate_type> next_pt = poly[i]; + encompass(extents_rectangle, next_pt); + modify_pt(poly[i-1], prev_pt, current_pt, next_pt, distance, multiplier); + prev_pt = current_pt; + current_pt = next_pt; + } + if(delta(extents_rectangle, HORIZONTAL) <= std::abs(2*distance)) + return false; + if(delta(extents_rectangle, VERTICAL) <= std::abs(2*distance)) + return false; + point_data<coordinate_type> next_pt = first_pt; + modify_pt(poly[poly.size()-2], prev_pt, current_pt, next_pt, distance, multiplier); + prev_pt = current_pt; + current_pt = next_pt; + next_pt = second_pt; + modify_pt(poly[0], prev_pt, current_pt, next_pt, distance, multiplier); + poly.back() = poly.front(); + //if the line segments formed between orignial and new points cross for an edge that edge inverts + //if all edges invert the polygon should be discarded + //if even one edge does not invert return true because the polygon is valid + bool non_inverting_edge = false; + for(std::size_t i = 1; i < poly.size(); ++i) { + std::pair<point_data<coordinate_type>, point_data<coordinate_type> > + he1(poly[i], orig_poly[i]), + he2(poly[i-1], orig_poly[i-1]); + if(!scanline_base<coordinate_type>::intersects(he1, he2)) { + non_inverting_edge = true; + break; + } + } + return non_inverting_edge; + } + + polygon_set_data& + bloat(typename coordinate_traits<coordinate_type>::unsigned_area_type distance) { + std::list<polygon_with_holes_data<coordinate_type> > polys; + get(polys); + clear(); + for(typename std::list<polygon_with_holes_data<coordinate_type> >::iterator itr = polys.begin(); + itr != polys.end(); ++itr) { + resize_poly_up((*itr).self_.coords_, (coordinate_type)distance, (coordinate_type)1); + insert_vertex_sequence((*itr).self_.begin(), (*itr).self_.end(), COUNTERCLOCKWISE, false); //inserts without holes + for(typename std::list<polygon_data<coordinate_type> >::iterator itrh = (*itr).holes_.begin(); + itrh != (*itr).holes_.end(); ++itrh) { + if(resize_poly_down((*itrh).coords_, (coordinate_type)distance, (coordinate_type)1)) { + insert_vertex_sequence((*itrh).coords_.begin(), (*itrh).coords_.end(), CLOCKWISE, true); + } + } + } + return *this; + } + + polygon_set_data& + shrink(typename coordinate_traits<coordinate_type>::unsigned_area_type distance) { + std::list<polygon_with_holes_data<coordinate_type> > polys; + get(polys); + clear(); + for(typename std::list<polygon_with_holes_data<coordinate_type> >::iterator itr = polys.begin(); + itr != polys.end(); ++itr) { + if(resize_poly_down((*itr).self_.coords_, (coordinate_type)distance, (coordinate_type)-1)) { + insert_vertex_sequence((*itr).self_.begin(), (*itr).self_.end(), COUNTERCLOCKWISE, false); //inserts without holes + for(typename std::list<polygon_data<coordinate_type> >::iterator itrh = (*itr).holes_.begin(); + itrh != (*itr).holes_.end(); ++itrh) { + resize_poly_up((*itrh).coords_, (coordinate_type)distance, (coordinate_type)-1); + insert_vertex_sequence((*itrh).coords_.begin(), (*itrh).coords_.end(), CLOCKWISE, true); + } + } + } + return *this; + } + + // TODO:: should be private + template <typename geometry_type> + inline polygon_set_data& + insert_with_resize(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc=false, unsigned int num_circle_segments=0, bool hole = false) { + return insert_with_resize_dispatch(poly, resizing, corner_fill_arc, num_circle_segments, hole, typename geometry_concept<geometry_type>::type()); + } + + template <typename geometry_type> + inline polygon_set_data& + insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole, + polygon_with_holes_concept tag) { + insert_with_resize_dispatch(poly, resizing, corner_fill_arc, num_circle_segments, hole, polygon_concept()); + for(typename polygon_with_holes_traits<geometry_type>::iterator_holes_type itr = + begin_holes(poly); itr != end_holes(poly); + ++itr) { + insert_with_resize_dispatch(*itr, resizing, corner_fill_arc, num_circle_segments, !hole, polygon_concept()); + } + return *this; + } + + template <typename geometry_type> + inline polygon_set_data& + insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole, + polygon_concept tag) { + + if (resizing==0) + return *this; + + + // one dimensional used to store CCW/CW flag + //direction_1d wdir = winding(poly); + // LOW==CLOCKWISE just faster to type + // so > 0 is CCW + //int multiplier = wdir == LOW ? -1 : 1; + //std::cout<<" multiplier : "<<multiplier<<std::endl; + //if(hole) resizing *= -1; + direction_1d resize_wdir = resizing>0?COUNTERCLOCKWISE:CLOCKWISE; + + typedef typename polygon_data<T>::iterator_type piterator; + piterator first, second, third, end, real_end; + real_end = end_points(poly); + third = begin_points(poly); + first = third; + if(first == real_end) return *this; + ++third; + if(third == real_end) return *this; + second = end = third; + ++third; + if(third == real_end) return *this; + + // for 1st corner + std::vector<point_data<T> > first_pts; + std::vector<point_data<T> > all_pts; + direction_1d first_wdir = CLOCKWISE; + + // for all corners + polygon_set_data<T> sizingSet; + bool sizing_sign = resizing<0; + bool prev_concave = true; + point_data<T> prev_point; + //int iCtr=0; + + + //insert minkofski shapes on edges and corners + do { // REAL WORK IS HERE + + + //first, second and third point to points in correct CCW order + // check if convex or concave case + point_data<coordinate_type> normal1( second->y()-first->y(), first->x()-second->x()); + point_data<coordinate_type> normal2( third->y()-second->y(), second->x()-third->x()); + double direction = normal1.x()*normal2.y()- normal2.x()*normal1.y(); + bool convex = direction>0; + + bool treat_as_concave = !convex; + if(sizing_sign) + treat_as_concave = convex; + point_data<double> v; + assign(v, normal1); + double s2 = (v.x()*v.x()+v.y()*v.y()); + double s = sqrt(s2)/resizing; + v = point_data<double>(v.x()/s,v.y()/s); + point_data<T> curr_prev; + if (prev_concave) + //TODO missing round_down() + curr_prev = point_data<T>(first->x()+v.x(),first->y()+v.y()); + else + curr_prev = prev_point; + + // around concave corners - insert rectangle + // if previous corner is concave it's point info may be ignored + if ( treat_as_concave) { + std::vector<point_data<T> > pts; + + pts.push_back(point_data<T>(second->x()+v.x(),second->y()+v.y())); + pts.push_back(*second); + pts.push_back(*first); + pts.push_back(point_data<T>(curr_prev)); + if (first_pts.size()){ + sizingSet.insert_vertex_sequence(pts.begin(),pts.end(), resize_wdir,false); + }else { + first_pts=pts; + first_wdir = resize_wdir; + } + } else { + + // add either intersection_quad or pie_shape, based on corner_fill_arc option + // for convex corner (convexity depends on sign of resizing, whether we shrink or grow) + std::vector< std::vector<point_data<T> > > pts; + direction_1d winding; + winding = convex?COUNTERCLOCKWISE:CLOCKWISE; + if (make_resizing_vertex_list(pts, curr_prev, prev_concave, *first, *second, *third, resizing + , num_circle_segments, corner_fill_arc)) + { + if (first_pts.size()) { + for (int i=0; i<pts.size(); i++) { + sizingSet.insert_vertex_sequence(pts[i].begin(),pts[i].end(),winding,false); + } + + } else { + first_pts = pts[0]; + first_wdir = resize_wdir; + for (int i=1; i<pts.size(); i++) { + sizingSet.insert_vertex_sequence(pts[i].begin(),pts[i].end(),winding,false); + } + } + prev_point = curr_prev; + + } else { + treat_as_concave = true; + } + } + + prev_concave = treat_as_concave; + first = second; + second = third; + ++third; + if(third == real_end) { + third = begin_points(poly); + if(*second == *third) { + ++third; //skip first point if it is duplicate of last point + } + } + } while(second != end); + + // handle insertion of first point + if (!prev_concave) { + first_pts[first_pts.size()-1]=prev_point; + } + sizingSet.insert_vertex_sequence(first_pts.begin(),first_pts.end(),first_wdir,false); + + polygon_set_data<coordinate_type> tmp; + + //insert original shape + tmp.insert(poly, false, polygon_concept()); + if((resizing < 0) ^ hole) tmp -= sizingSet; + else tmp += sizingSet; + //tmp.clean(); + insert(tmp, hole); + return (*this); + } + + + inline polygon_set_data& + interact(const polygon_set_data& that); + + inline bool downcast(polygon_45_set_data<coordinate_type>& result) const { + if(!is_45_) return false; + for(iterator_type itr = begin(); itr != end(); ++itr) { + const element_type& elem = *itr; + int count = elem.second; + int rise = 1; //up sloping 45 + if(scanline_base<coordinate_type>::is_horizontal(elem.first)) rise = 0; + else if(scanline_base<coordinate_type>::is_vertical(elem.first)) rise = 2; + else { + if(!scanline_base<coordinate_type>::is_45_degree(elem.first)) { + is_45_ = false; + return false; //consider throwing because is_45_ has be be wrong + } + if(elem.first.first.y() > elem.first.second.y()) rise = -1; //down sloping 45 + } + typename polygon_45_set_data<coordinate_type>::Vertex45Compact vertex(elem.first.first, rise, count); + result.insert(vertex); + typename polygon_45_set_data<coordinate_type>::Vertex45Compact vertex2(elem.first.second, rise, -count); + result.insert(vertex2); + } + return true; + } + + inline GEOMETRY_CONCEPT_ID concept_downcast() const { + typedef typename coordinate_traits<coordinate_type>::coordinate_difference delta_type; + bool is_45 = false; + for(iterator_type itr = begin(); itr != end(); ++itr) { + const element_type& elem = *itr; + delta_type h_delta = euclidean_distance(elem.first.first, elem.first.second, HORIZONTAL); + delta_type v_delta = euclidean_distance(elem.first.first, elem.first.second, VERTICAL); + if(h_delta != 0 || v_delta != 0) { + //neither delta is zero and the edge is not MANHATTAN + if(v_delta != h_delta && v_delta != -h_delta) return POLYGON_SET_CONCEPT; + else is_45 = true; + } + } + if(is_45) return POLYGON_45_SET_CONCEPT; + return POLYGON_90_SET_CONCEPT; + } + + private: + mutable value_type data_; + mutable bool dirty_; + mutable bool unsorted_; + mutable bool is_45_; + + private: + //functions + + template <typename output_container> + void get_dispatch(output_container& output, polygon_concept tag) const { + get_fracture(output, true, tag); + } + template <typename output_container> + void get_dispatch(output_container& output, polygon_with_holes_concept tag) const { + get_fracture(output, false, tag); + } + template <typename output_container, typename concept_type> + void get_fracture(output_container& container, bool fracture_holes, concept_type ) const { + clean(); + polygon_arbitrary_formation<coordinate_type> pf(fracture_holes); + typedef typename polygon_arbitrary_formation<coordinate_type>::vertex_half_edge vertex_half_edge; + std::vector<vertex_half_edge> data; + for(iterator_type itr = data_.begin(); itr != data_.end(); ++itr){ + data.push_back(vertex_half_edge((*itr).first.first, (*itr).first.second, (*itr).second)); + data.push_back(vertex_half_edge((*itr).first.second, (*itr).first.first, -1 * (*itr).second)); + } + gtlsort(data.begin(), data.end()); + pf.scan(container, data.begin(), data.end()); + } + }; + + struct polygon_set_concept; + template <typename T> + struct geometry_concept<polygon_set_data<T> > { + typedef polygon_set_concept type; + }; + +// template <typename T> +// inline double compute_area(point_data<T>& a, point_data<T>& b, point_data<T>& c) { + +// return (double)(b.x()-a.x())*(double)(c.y()-a.y())- (double)(c.x()-a.x())*(double)(b.y()-a.y()); + + +// } + + template <typename T> + inline int make_resizing_vertex_list(std::vector<std::vector<point_data< T> > >& return_points, + point_data<T>& curr_prev, bool ignore_prev_point, + point_data< T> start, point_data<T> middle, point_data< T> end, + double sizing_distance, unsigned int num_circle_segments, bool corner_fill_arc) { + + // handle the case of adding an intersection point + point_data<double> dn1( middle.y()-start.y(), start.x()-middle.x()); + double size = sizing_distance/sqrt( dn1.x()*dn1.x()+dn1.y()*dn1.y()); + dn1 = point_data<double>( dn1.x()*size, dn1.y()* size); + point_data<double> dn2( end.y()-middle.y(), middle.x()-end.x()); + size = sizing_distance/sqrt( dn2.x()*dn2.x()+dn2.y()*dn2.y()); + dn2 = point_data<double>( dn2.x()*size, dn2.y()* size); + point_data<double> start_offset((start.x()+dn1.x()),(start.y()+dn1.y())); + point_data<double> mid1_offset((middle.x()+dn1.x()),(middle.y()+dn1.y())); + point_data<double> end_offset((end.x()+dn2.x()),(end.y()+dn2.y())); + point_data<double> mid2_offset((middle.x()+dn2.x()),(middle.y()+dn2.y())); + if (ignore_prev_point) + curr_prev = round_down<T>(start_offset); + + + if (corner_fill_arc) { + std::vector<point_data< T> > return_points1; + return_points.push_back(return_points1); + std::vector<point_data< T> >& return_points_back = return_points[return_points.size()-1]; + return_points_back.push_back(round_down<T>(mid1_offset)); + return_points_back.push_back(middle); + return_points_back.push_back(start); + return_points_back.push_back(curr_prev); + point_data<double> dmid(middle.x(),middle.y()); + return_points.push_back(return_points1); + int num = make_arc(return_points[return_points.size()-1],mid1_offset,mid2_offset,dmid,sizing_distance,num_circle_segments); + curr_prev = round_down<T>(mid2_offset); + return num; + + } + + std::pair<point_data<double>,point_data<double> > he1(start_offset,mid1_offset); + std::pair<point_data<double>,point_data<double> > he2(mid2_offset ,end_offset); + //typedef typename high_precision_type<double>::type high_precision; + + point_data<T> intersect; + typename scanline_base<T>::compute_intersection_pack pack; + bool res = pack.compute_intersection(intersect,he1,he2,true); + if( res ) { + std::vector<point_data< T> > return_points1; + return_points.push_back(return_points1); + std::vector<point_data< T> >& return_points_back = return_points[return_points.size()-1]; + return_points_back.push_back(intersect); + return_points_back.push_back(middle); + return_points_back.push_back(start); + return_points_back.push_back(curr_prev); + + //double d1= compute_area(intersect,middle,start); + //double d2= compute_area(start,curr_prev,intersect); + + curr_prev = intersect; + + + return return_points.size(); + } + return 0; + + } + + // this routine should take in start and end point s.t. end point is CCW from start + // it sould make a pie slice polygon that is an intersection of that arc + // with an ngon segments approximation of the circle centered at center with radius r + // point start is gauaranteed to be on the segmentation + // returnPoints will start with the first point after start + // returnPoints vector may be empty + template <typename T> + inline int make_arc(std::vector<point_data< T> >& return_points, + point_data< double> start, point_data< double> end, + point_data< double> center, double r, unsigned int num_circle_segments) { + const double our_pi=3.1415926535897932384626433832795028841971; + + // derive start and end angles + double ps = atan2(start.y()-center.y(), start.x()-center.x()); + double pe = atan2(end.y()-center.y(), end.x()-center.x()); + if (ps < 0.0) + ps += 2.0 * our_pi; + if (pe <= 0.0) + pe += 2.0 * our_pi; + if (ps >= 2.0 * our_pi) + ps -= 2.0 * our_pi; + while (pe <= ps) + pe += 2.0 * our_pi; + double delta_angle = (2.0 * our_pi) / (double)num_circle_segments; + if ( start==end) // full circle? + { + ps = delta_angle*0.5; + pe = ps + our_pi * 2.0; + double x,y; + x = center.x() + r * cos(ps); + y = center.y() + r * sin(ps); + start = point_data<double>(x,y); + end = start; + } + return_points.push_back(round_down<T>(center)); + return_points.push_back(round_down<T>(start)); + unsigned int i=0; + double curr_angle = ps+delta_angle; + while( curr_angle < pe - 0.01 && i < 2 * num_circle_segments) { + i++; + double x = center.x() + r * cos( curr_angle); + double y = center.y() + r * sin( curr_angle); + return_points.push_back( round_down<T>((point_data<double>(x,y)))); + curr_angle+=delta_angle; + } + return_points.push_back(round_down<T>(end)); + return return_points.size(); + } + +}// close namespace +}// close name space + +#include "detail/scan_arbitrary.hpp" + +namespace boost { namespace polygon { + //ConnectivityExtraction computes the graph of connectivity between rectangle, polygon and + //polygon set graph nodes where an edge is created whenever the geometry in two nodes overlap + template <typename coordinate_type> + class connectivity_extraction{ + private: + typedef arbitrary_connectivity_extraction<coordinate_type, int> ce; + ce ce_; + unsigned int nodeCount_; + public: + inline connectivity_extraction() : ce_(), nodeCount_(0) {} + inline connectivity_extraction(const connectivity_extraction& that) : ce_(that.ce_), + nodeCount_(that.nodeCount_) {} + inline connectivity_extraction& operator=(const connectivity_extraction& that) { + ce_ = that.ce_; + nodeCount_ = that.nodeCount_; {} + return *this; + } + + //insert a polygon set graph node, the value returned is the id of the graph node + inline unsigned int insert(const polygon_set_data<coordinate_type>& ps) { + ps.clean(); + ce_.populateTouchSetData(ps.begin(), ps.end(), nodeCount_); + return nodeCount_++; + } + template <class GeoObjT> + inline unsigned int insert(const GeoObjT& geoObj) { + polygon_set_data<coordinate_type> ps; + ps.insert(geoObj); + return insert(ps); + } + + //extract connectivity and store the edges in the graph + //graph must be indexable by graph node id and the indexed value must be a std::set of + //graph node id + template <class GraphT> + inline void extract(GraphT& graph) { + ce_.execute(graph); + } + }; + + template <typename T> + polygon_set_data<T>& + polygon_set_data<T>::interact(const polygon_set_data<T>& that) { + connectivity_extraction<coordinate_type> ce; + std::vector<polygon_with_holes_data<T> > polys; + get(polys); + clear(); + for(std::size_t i = 0; i < polys.size(); ++i) { + ce.insert(polys[i]); + } + int id = ce.insert(that); + std::vector<std::set<int> > graph(id+1); + ce.extract(graph); + for(std::set<int>::iterator itr = graph[id].begin(); + itr != graph[id].end(); ++itr) { + insert(polys[*itr]); + } + return *this; + } +} +} + +#include "polygon_set_traits.hpp" +#include "detail/polygon_set_view.hpp" + +#include "polygon_set_concept.hpp" +#include "detail/minkowski.hpp" +#endif + diff --git a/boost/polygon/polygon_set_traits.hpp b/boost/polygon/polygon_set_traits.hpp new file mode 100644 index 0000000000..93604c4931 --- /dev/null +++ b/boost/polygon/polygon_set_traits.hpp @@ -0,0 +1,130 @@ +/* + 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_POLYGON_SET_TRAITS_HPP +#define BOOST_POLYGON_POLYGON_SET_TRAITS_HPP +namespace boost { namespace polygon{ + + struct polygon_set_concept {}; + + //default definition of polygon set traits works for any model of polygon , polygon with holes or any vector or list thereof + template <typename T> + struct polygon_set_traits { + typedef typename get_coordinate_type<T, typename geometry_concept<T>::type >::type coordinate_type; + typedef typename get_iterator_type<T>::type iterator_type; + typedef T operator_arg_type; + + static inline iterator_type begin(const T& polygon_set) { + return get_iterator_type<T>::begin(polygon_set); + } + + static inline iterator_type end(const T& polygon_set) { + return get_iterator_type<T>::end(polygon_set); + } + + static inline bool clean(const T& ) { return false; } + + static inline bool sorted(const T& ) { return false; } + }; + + template <typename T> + struct is_polygonal_concept { typedef gtl_no type; }; + template <> + struct is_polygonal_concept<polygon_concept> { typedef gtl_yes type; }; + template <> + struct is_polygonal_concept<polygon_with_holes_concept> { typedef gtl_yes type; }; + template <> + struct is_polygonal_concept<polygon_set_concept> { typedef gtl_yes type; }; + + template <typename T> + struct is_polygon_set_type { + typedef typename is_polygonal_concept<typename geometry_concept<T>::type>::type type; + }; + template <typename T> + struct is_polygon_set_type<std::list<T> > { + typedef typename gtl_or< + typename is_polygonal_concept<typename geometry_concept<std::list<T> >::type>::type, + typename is_polygonal_concept<typename geometry_concept<typename std::list<T>::value_type>::type>::type>::type type; + }; + template <typename T> + struct is_polygon_set_type<std::vector<T> > { + typedef typename gtl_or< + typename is_polygonal_concept<typename geometry_concept<std::vector<T> >::type>::type, + typename is_polygonal_concept<typename geometry_concept<typename std::vector<T>::value_type>::type>::type>::type type; + }; + + template <typename T> + struct is_mutable_polygon_set_type { + typedef typename gtl_same_type<polygon_set_concept, typename geometry_concept<T>::type>::type type; + }; + template <typename T> + struct is_mutable_polygon_set_type<std::list<T> > { + typedef typename gtl_or< + typename gtl_same_type<polygon_set_concept, typename geometry_concept<std::list<T> >::type>::type, + typename is_polygonal_concept<typename geometry_concept<typename std::list<T>::value_type>::type>::type>::type type; + }; + template <typename T> + struct is_mutable_polygon_set_type<std::vector<T> > { + typedef typename gtl_or< + typename gtl_same_type<polygon_set_concept, typename geometry_concept<std::vector<T> >::type>::type, + typename is_polygonal_concept<typename geometry_concept<typename std::vector<T>::value_type>::type>::type>::type type; + }; + + template <typename T> + struct polygon_set_mutable_traits {}; + template <typename T> + struct polygon_set_mutable_traits<std::list<T> > { + template <typename input_iterator_type> + static inline void set(std::list<T>& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { + polygon_set.clear(); + polygon_set_data<typename polygon_set_traits<std::list<T> >::coordinate_type> ps; + ps.insert(input_begin, input_end); + ps.get(polygon_set); + } + }; + template <typename T> + struct polygon_set_mutable_traits<std::vector<T> > { + template <typename input_iterator_type> + static inline void set(std::vector<T>& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { + polygon_set.clear(); + polygon_set_data<typename polygon_set_traits<std::list<T> >::coordinate_type> ps; + ps.insert(input_begin, input_end); + ps.get(polygon_set); + } + }; + + template <typename T> + struct polygon_set_mutable_traits<polygon_set_data<T> > { + template <typename input_iterator_type> + static inline void set(polygon_set_data<T>& polygon_set, + input_iterator_type input_begin, input_iterator_type input_end) { + polygon_set.set(input_begin, input_end); + } + }; + template <typename T> + struct polygon_set_traits<polygon_set_data<T> > { + typedef typename polygon_set_data<T>::coordinate_type coordinate_type; + typedef typename polygon_set_data<T>::iterator_type iterator_type; + typedef typename polygon_set_data<T>::operator_arg_type operator_arg_type; + + static inline iterator_type begin(const polygon_set_data<T>& polygon_set) { + return polygon_set.begin(); + } + + static inline iterator_type end(const polygon_set_data<T>& polygon_set) { + return polygon_set.end(); + } + + static inline bool clean(const polygon_set_data<T>& polygon_set) { polygon_set.clean(); return true; } + + static inline bool sorted(const polygon_set_data<T>& polygon_set) { polygon_set.sort(); return true; } + + }; +} +} +#endif + diff --git a/boost/polygon/polygon_traits.hpp b/boost/polygon/polygon_traits.hpp new file mode 100644 index 0000000000..041321d22b --- /dev/null +++ b/boost/polygon/polygon_traits.hpp @@ -0,0 +1,1859 @@ +/* + 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_POLYGON_TRAITS_HPP +#define BOOST_POLYGON_POLYGON_TRAITS_HPP +namespace boost { namespace polygon{ + + template <typename T, typename enable = gtl_yes> + struct polygon_90_traits { + typedef typename T::coordinate_type coordinate_type; + typedef typename T::compact_iterator_type compact_iterator_type; + + // Get the begin iterator + static inline compact_iterator_type begin_compact(const T& t) { + return t.begin_compact(); + } + + // Get the end iterator + static inline compact_iterator_type end_compact(const T& t) { + return t.end_compact(); + } + + // Get the number of sides of the polygon + static inline std::size_t size(const T& t) { + return t.size(); + } + + // Get the winding direction of the polygon + static inline winding_direction winding(const T&) { + return unknown_winding; + } + }; + + template <typename T> + struct polygon_traits_general { + typedef typename T::coordinate_type coordinate_type; + typedef typename T::iterator_type iterator_type; + typedef typename T::point_type point_type; + + // Get the begin iterator + static inline iterator_type begin_points(const T& t) { + return t.begin(); + } + + // Get the end iterator + static inline iterator_type end_points(const T& t) { + return t.end(); + } + + // Get the number of sides of the polygon + static inline std::size_t size(const T& t) { + return t.size(); + } + + // Get the winding direction of the polygon + static inline winding_direction winding(const T&) { + return unknown_winding; + } + }; + + template <typename T> + struct polygon_traits_90 { + typedef typename polygon_90_traits<T>::coordinate_type coordinate_type; + typedef iterator_compact_to_points<typename polygon_90_traits<T>::compact_iterator_type, point_data<coordinate_type> > iterator_type; + typedef point_data<coordinate_type> point_type; + + // Get the begin iterator + static inline iterator_type begin_points(const T& t) { + return iterator_type(polygon_90_traits<T>::begin_compact(t), + polygon_90_traits<T>::end_compact(t)); + } + + // Get the end iterator + static inline iterator_type end_points(const T& t) { + return iterator_type(polygon_90_traits<T>::end_compact(t), + polygon_90_traits<T>::end_compact(t)); + } + + // Get the number of sides of the polygon + static inline std::size_t size(const T& t) { + return polygon_90_traits<T>::size(t); + } + + // Get the winding direction of the polygon + static inline winding_direction winding(const T& t) { + return polygon_90_traits<T>::winding(t); + } + }; + +#ifndef BOOST_VERY_LITTLE_SFINAE + + template <typename T, typename enable = gtl_yes> + struct polygon_traits {}; + + template <typename T> + struct polygon_traits<T, + typename gtl_or_4< + typename gtl_same_type<typename geometry_concept<T>::type, polygon_concept>::type, + typename gtl_same_type<typename geometry_concept<T>::type, polygon_45_concept>::type, + typename gtl_same_type<typename geometry_concept<T>::type, polygon_with_holes_concept>::type, + typename gtl_same_type<typename geometry_concept<T>::type, polygon_45_with_holes_concept>::type + >::type> : public polygon_traits_general<T> {}; + + template <typename T> + struct polygon_traits< T, + typename gtl_or< + typename gtl_same_type<typename geometry_concept<T>::type, polygon_90_concept>::type, + typename gtl_same_type<typename geometry_concept<T>::type, polygon_90_with_holes_concept>::type + >::type > : public polygon_traits_90<T> {}; + +#else + + template <typename T, typename T_IF, typename T_ELSE> + struct gtl_ifelse {}; + template <typename T_IF, typename T_ELSE> + struct gtl_ifelse<gtl_no, T_IF, T_ELSE> { + typedef T_ELSE type; + }; + template <typename T_IF, typename T_ELSE> + struct gtl_ifelse<gtl_yes, T_IF, T_ELSE> { + typedef T_IF type; + }; + + template <typename T, typename enable = gtl_yes> + struct polygon_traits {}; + + template <typename T> + struct polygon_traits<T, typename gtl_or<typename gtl_or_4< + typename gtl_same_type<typename geometry_concept<T>::type, polygon_concept>::type, + typename gtl_same_type<typename geometry_concept<T>::type, polygon_45_concept>::type, + typename gtl_same_type<typename geometry_concept<T>::type, polygon_with_holes_concept>::type, + typename gtl_same_type<typename geometry_concept<T>::type, polygon_45_with_holes_concept>::type + >::type, typename gtl_or< + typename gtl_same_type<typename geometry_concept<T>::type, polygon_90_concept>::type, + typename gtl_same_type<typename geometry_concept<T>::type, polygon_90_with_holes_concept>::type + >::type>::type > : public gtl_ifelse<typename gtl_or< + typename gtl_same_type<typename geometry_concept<T>::type, polygon_90_concept>::type, + typename gtl_same_type<typename geometry_concept<T>::type, polygon_90_with_holes_concept>::type >::type, + polygon_traits_90<T>, + polygon_traits_general<T> >::type { + }; + +#endif + + template <typename T, typename enable = void> + struct polygon_with_holes_traits { + typedef typename T::iterator_holes_type iterator_holes_type; + typedef typename T::hole_type hole_type; + + // Get the begin iterator + static inline iterator_holes_type begin_holes(const T& t) { + return t.begin_holes(); + } + + // Get the end iterator + static inline iterator_holes_type end_holes(const T& t) { + return t.end_holes(); + } + + // Get the number of holes + static inline std::size_t size_holes(const T& t) { + return t.size_holes(); + } + }; + + template <typename T, typename enable = void> + struct polygon_90_mutable_traits { + + // Set the data of a polygon with the unique coordinates in an iterator, starting with an x + template <typename iT> + static inline T& set_compact(T& t, iT input_begin, iT input_end) { + t.set_compact(input_begin, input_end); + return t; + } + + }; + + template <typename T> + struct polygon_90_mutable_traits<T, typename gtl_same_type<polygon_concept, typename geometry_concept<T>::type>::type> { + // Set the data of a polygon with the unique coordinates in an iterator, starting with an x + template <typename iT> + static inline T& set_compact(T& t, iT input_begin, iT input_end) { + typedef iterator_points_to_compact<iT, typename polygon_traits<T>::point_type> iTp; + t.set_points(iTp(polygon_traits<T>::begin_points(t)), iTp(polygon_traits<T>::end_points(t))); + return t; + } + }; + + template <typename T, typename enable = void> + struct polygon_mutable_traits { + + // Set the data of a polygon with the unique coordinates in an iterator, starting with an x + template <typename iT> + static inline T& set_points(T& t, iT input_begin, iT input_end) { + t.set(input_begin, input_end); + return t; + } + + }; + + template <typename T, typename enable = void> + struct polygon_with_holes_mutable_traits { + + // Set the data of a polygon with the unique coordinates in an iterator, starting with an x + template <typename iT> + static inline T& set_holes(T& t, iT inputBegin, iT inputEnd) { + t.set_holes(inputBegin, inputEnd); + return t; + } + + }; +} +} +#include "isotropy.hpp" + +//point +#include "point_data.hpp" +#include "point_traits.hpp" +#include "point_concept.hpp" + +//interval +#include "interval_data.hpp" +#include "interval_traits.hpp" +#include "interval_concept.hpp" + +//rectangle +#include "rectangle_data.hpp" +#include "rectangle_traits.hpp" +#include "rectangle_concept.hpp" + +//algorithms needed by polygon types +#include "detail/iterator_points_to_compact.hpp" +#include "detail/iterator_compact_to_points.hpp" + +//polygons +#include "polygon_45_data.hpp" +#include "polygon_data.hpp" +#include "polygon_90_data.hpp" +#include "polygon_90_with_holes_data.hpp" +#include "polygon_45_with_holes_data.hpp" +#include "polygon_with_holes_data.hpp" + +namespace boost { namespace polygon{ + struct polygon_concept {}; + struct polygon_with_holes_concept {}; + struct polygon_45_concept {}; + struct polygon_45_with_holes_concept {}; + struct polygon_90_concept {}; + struct polygon_90_with_holes_concept {}; + + + template <typename T> + struct is_polygon_90_type { + typedef typename geometry_concept<T>::type GC; + typedef typename gtl_same_type<polygon_90_concept, GC>::type type; + }; + + template <typename T> + struct is_polygon_45_type { + typedef typename geometry_concept<T>::type GC; + typedef typename gtl_or<typename is_polygon_90_type<T>::type, + typename gtl_same_type<polygon_45_concept, GC>::type>::type type; + }; + + template <typename T> + struct is_polygon_type { + typedef typename geometry_concept<T>::type GC; + typedef typename gtl_or<typename is_polygon_45_type<T>::type, + typename gtl_same_type<polygon_concept, GC>::type>::type type; + }; + + template <typename T> + struct is_polygon_90_with_holes_type { + typedef typename geometry_concept<T>::type GC; + typedef typename gtl_or<typename is_polygon_90_type<T>::type, + typename gtl_same_type<polygon_90_with_holes_concept, GC>::type>::type type; + }; + + template <typename T> + struct is_polygon_45_with_holes_type { + typedef typename geometry_concept<T>::type GC; + typedef typename gtl_or_3<typename is_polygon_90_with_holes_type<T>::type, + typename is_polygon_45_type<T>::type, + typename gtl_same_type<polygon_45_with_holes_concept, GC>::type>::type type; + }; + + template <typename T> + struct is_polygon_with_holes_type { + typedef typename geometry_concept<T>::type GC; + typedef typename gtl_or_3<typename is_polygon_45_with_holes_type<T>::type, + typename is_polygon_type<T>::type, + typename gtl_same_type<polygon_with_holes_concept, GC>::type>::type type; + }; + + template <typename T> + struct is_mutable_polygon_90_type { + typedef typename geometry_concept<T>::type GC; + typedef typename gtl_same_type<polygon_90_concept, GC>::type type; + }; + + template <typename T> + struct is_mutable_polygon_45_type { + typedef typename geometry_concept<T>::type GC; + typedef typename gtl_same_type<polygon_45_concept, GC>::type type; + }; + + template <typename T> + struct is_mutable_polygon_type { + typedef typename geometry_concept<T>::type GC; + typedef typename gtl_same_type<polygon_concept, GC>::type type; + }; + + template <typename T> + struct is_mutable_polygon_90_with_holes_type { + typedef typename geometry_concept<T>::type GC; + typedef typename gtl_same_type<polygon_90_with_holes_concept, GC>::type type; + }; + + template <typename T> + struct is_mutable_polygon_45_with_holes_type { + typedef typename geometry_concept<T>::type GC; + typedef typename gtl_same_type<polygon_45_with_holes_concept, GC>::type type; + }; + + template <typename T> + struct is_mutable_polygon_with_holes_type { + typedef typename geometry_concept<T>::type GC; + typedef typename gtl_same_type<polygon_with_holes_concept, GC>::type type; + }; + + template <typename T> + struct is_any_mutable_polygon_with_holes_type { + typedef typename gtl_or_3<typename is_mutable_polygon_90_with_holes_type<T>::type, + typename is_mutable_polygon_45_with_holes_type<T>::type, + typename is_mutable_polygon_with_holes_type<T>::type>::type type; + }; + template <typename T> + struct is_any_mutable_polygon_without_holes_type { + typedef typename gtl_or_3< + typename is_mutable_polygon_90_type<T>::type, + typename is_mutable_polygon_45_type<T>::type, + typename is_mutable_polygon_type<T>::type>::type type; }; + + template <typename T> + struct is_any_mutable_polygon_type { + typedef typename gtl_or<typename is_any_mutable_polygon_with_holes_type<T>::type, + typename is_any_mutable_polygon_without_holes_type<T>::type>::type type; + }; + + template <typename T> + struct polygon_from_polygon_with_holes_type {}; + template <> + struct polygon_from_polygon_with_holes_type<polygon_with_holes_concept> { typedef polygon_concept type; }; + template <> + struct polygon_from_polygon_with_holes_type<polygon_45_with_holes_concept> { typedef polygon_45_concept type; }; + template <> + struct polygon_from_polygon_with_holes_type<polygon_90_with_holes_concept> { typedef polygon_90_concept type; }; + + template <> + struct geometry_domain<polygon_45_concept> { typedef forty_five_domain type; }; + template <> + struct geometry_domain<polygon_45_with_holes_concept> { typedef forty_five_domain type; }; + template <> + struct geometry_domain<polygon_90_concept> { typedef manhattan_domain type; }; + template <> + struct geometry_domain<polygon_90_with_holes_concept> { typedef manhattan_domain type; }; + + template <typename domain_type, typename coordinate_type> + struct distance_type_by_domain { typedef typename coordinate_traits<coordinate_type>::coordinate_distance type; }; + template <typename coordinate_type> + struct distance_type_by_domain<manhattan_domain, coordinate_type> { + typedef typename coordinate_traits<coordinate_type>::coordinate_difference type; }; + + // \brief Sets the boundary of the polygon to the points in the iterator range + // \tparam T A type that models polygon_concept + // \tparam iT Iterator type over objects that model point_concept + // \param t The polygon to set + // \param begin_points The start of the range of points + // \param end_points The end of the range of points + + /// \relatesalso polygon_concept + template <typename T, typename iT> + typename enable_if <typename is_any_mutable_polygon_type<T>::type, T>::type & + set_points(T& t, iT begin_points, iT end_points) { + polygon_mutable_traits<T>::set_points(t, begin_points, end_points); + return t; + } + + // \brief Sets the boundary of the polygon to the non-redundant coordinates in the iterator range + // \tparam T A type that models polygon_90_concept + // \tparam iT Iterator type over objects that model coordinate_concept + // \param t The polygon to set + // \param begin_compact_coordinates The start of the range of coordinates + // \param end_compact_coordinates The end of the range of coordinates + +/// \relatesalso polygon_90_concept + template <typename T, typename iT> + typename enable_if <typename gtl_or< + typename is_mutable_polygon_90_type<T>::type, + typename is_mutable_polygon_90_with_holes_type<T>::type>::type, T>::type & + set_compact(T& t, iT begin_compact_coordinates, iT end_compact_coordinates) { + polygon_90_mutable_traits<T>::set_compact(t, begin_compact_coordinates, end_compact_coordinates); + return t; + } + +/// \relatesalso polygon_with_holes_concept + template <typename T, typename iT> + typename enable_if< typename gtl_and < + typename is_any_mutable_polygon_with_holes_type<T>::type, + typename gtl_different_type<typename geometry_domain<typename geometry_concept<T>::type>::type, + manhattan_domain>::type>::type, + T>::type & + set_compact(T& t, iT begin_compact_coordinates, iT end_compact_coordinates) { + iterator_compact_to_points<iT, point_data<typename polygon_traits<T>::coordinate_type> > + itrb(begin_compact_coordinates, end_compact_coordinates), + itre(end_compact_coordinates, end_compact_coordinates); + return set_points(t, itrb, itre); + } + +/// \relatesalso polygon_with_holes_concept + template <typename T, typename iT> + typename enable_if <typename is_any_mutable_polygon_with_holes_type<T>::type, T>::type & + set_holes(T& t, iT begin_holes, iT end_holes) { + polygon_with_holes_mutable_traits<T>::set_holes(t, begin_holes, end_holes); + return t; + } + +/// \relatesalso polygon_90_concept + template <typename T> + typename polygon_90_traits<T>::compact_iterator_type + begin_compact(const T& polygon, + typename enable_if< + typename gtl_and <typename is_polygon_with_holes_type<T>::type, + typename gtl_same_type<typename geometry_domain<typename geometry_concept<T>::type>::type, + manhattan_domain>::type>::type>::type * = 0 + ) { + return polygon_90_traits<T>::begin_compact(polygon); + } + +/// \relatesalso polygon_90_concept + template <typename T> + typename polygon_90_traits<T>::compact_iterator_type + end_compact(const T& polygon, + typename enable_if< + typename gtl_and <typename is_polygon_with_holes_type<T>::type, + typename gtl_same_type<typename geometry_domain<typename geometry_concept<T>::type>::type, + manhattan_domain>::type>::type>::type * = 0 + ) { + return polygon_90_traits<T>::end_compact(polygon); + } + + /// \relatesalso polygon_concept + template <typename T> + typename enable_if < typename gtl_if< + typename is_polygon_with_holes_type<T>::type>::type, + typename polygon_traits<T>::iterator_type>::type + begin_points(const T& polygon) { + return polygon_traits<T>::begin_points(polygon); + } + + /// \relatesalso polygon_concept + template <typename T> + typename enable_if < typename gtl_if< + typename is_polygon_with_holes_type<T>::type>::type, + typename polygon_traits<T>::iterator_type>::type + end_points(const T& polygon) { + return polygon_traits<T>::end_points(polygon); + } + + /// \relatesalso polygon_concept + template <typename T> + typename enable_if <typename is_polygon_with_holes_type<T>::type, + std::size_t>::type + size(const T& polygon) { + return polygon_traits<T>::size(polygon); + } + +/// \relatesalso polygon_with_holes_concept + template <typename T> + typename enable_if < typename gtl_if< + typename is_polygon_with_holes_type<T>::type>::type, + typename polygon_with_holes_traits<T>::iterator_holes_type>::type + begin_holes(const T& polygon) { + return polygon_with_holes_traits<T>::begin_holes(polygon); + } + +/// \relatesalso polygon_with_holes_concept + template <typename T> + typename enable_if < typename gtl_if< + typename is_polygon_with_holes_type<T>::type>::type, + typename polygon_with_holes_traits<T>::iterator_holes_type>::type + end_holes(const T& polygon) { + return polygon_with_holes_traits<T>::end_holes(polygon); + } + +/// \relatesalso polygon_with_holes_concept + template <typename T> + typename enable_if <typename is_polygon_with_holes_type<T>::type, + std::size_t>::type + size_holes(const T& polygon) { + return polygon_with_holes_traits<T>::size_holes(polygon); + } + + // \relatesalso polygon_concept + template <typename T1, typename T2> + typename enable_if< + typename gtl_and< typename is_mutable_polygon_type<T1>::type, + typename is_polygon_type<T2>::type>::type, T1>::type & + assign(T1& lvalue, const T2& rvalue) { + polygon_mutable_traits<T1>::set_points(lvalue, polygon_traits<T2>::begin_points(rvalue), + polygon_traits<T2>::end_points(rvalue)); + return lvalue; + } + +// \relatesalso polygon_with_holes_concept + template <typename T1, typename T2> + typename enable_if< + typename gtl_and< typename is_mutable_polygon_with_holes_type<T1>::type, + typename is_polygon_with_holes_type<T2>::type>::type, T1>::type & + assign(T1& lvalue, const T2& rvalue) { + polygon_mutable_traits<T1>::set_points(lvalue, polygon_traits<T2>::begin_points(rvalue), + polygon_traits<T2>::end_points(rvalue)); + polygon_with_holes_mutable_traits<T1>::set_holes(lvalue, polygon_with_holes_traits<T2>::begin_holes(rvalue), + polygon_with_holes_traits<T2>::end_holes(rvalue)); + return lvalue; + } + + // \relatesalso polygon_45_concept + template <typename T1, typename T2> + typename enable_if< typename gtl_and< typename is_mutable_polygon_45_type<T1>::type, typename is_polygon_45_type<T2>::type>::type, T1>::type & + assign(T1& lvalue, const T2& rvalue) { + polygon_mutable_traits<T1>::set_points(lvalue, polygon_traits<T2>::begin_points(rvalue), + polygon_traits<T2>::end_points(rvalue)); + return lvalue; + } + +// \relatesalso polygon_45_with_holes_concept + template <typename T1, typename T2> + typename enable_if< + typename gtl_and< typename is_mutable_polygon_45_with_holes_type<T1>::type, + typename is_polygon_45_with_holes_type<T2>::type>::type, T1>::type & + assign(T1& lvalue, const T2& rvalue) { + polygon_mutable_traits<T1>::set_points(lvalue, polygon_traits<T2>::begin_points(rvalue), + polygon_traits<T2>::end_points(rvalue)); + polygon_with_holes_mutable_traits<T1>::set_holes(lvalue, polygon_with_holes_traits<T2>::begin_holes(rvalue), + polygon_with_holes_traits<T2>::end_holes(rvalue)); + return lvalue; + } + + // \relatesalso polygon_90_concept + template <typename T1, typename T2> + typename enable_if< + typename gtl_and< typename is_mutable_polygon_90_type<T1>::type, + typename is_polygon_90_type<T2>::type>::type, T1>::type & + assign(T1& lvalue, const T2& rvalue) { + polygon_90_mutable_traits<T1>::set_compact(lvalue, polygon_90_traits<T2>::begin_compact(rvalue), + polygon_90_traits<T2>::end_compact(rvalue)); + return lvalue; + } + +// \relatesalso polygon_90_with_holes_concept + template <typename T1, typename T2> + typename enable_if< + typename gtl_and< typename is_mutable_polygon_90_with_holes_type<T1>::type, + typename is_polygon_90_with_holes_type<T2>::type>::type, T1>::type & + assign(T1& lvalue, const T2& rvalue) { + polygon_90_mutable_traits<T1>::set_compact(lvalue, polygon_90_traits<T2>::begin_compact(rvalue), + polygon_90_traits<T2>::end_compact(rvalue)); + polygon_with_holes_mutable_traits<T1>::set_holes(lvalue, polygon_with_holes_traits<T2>::begin_holes(rvalue), + polygon_with_holes_traits<T2>::end_holes(rvalue)); + return lvalue; + } + + // \relatesalso polygon_90_concept + template <typename T1, typename T2> + typename enable_if< + typename gtl_and< typename is_any_mutable_polygon_type<T1>::type, + typename is_rectangle_concept<typename geometry_concept<T2>::type>::type>::type, T1>::type & + assign(T1& polygon, const T2& rect) { + typedef point_data<typename polygon_traits<T1>::coordinate_type> PT; + PT points[4] = {PT(xl(rect), yl(rect)), PT(xh(rect), yl(rect)), PT(xh(rect), yh(rect)), PT(xl(rect), yh(rect))}; + set_points(polygon, points, points+4); + return polygon; + } + +/// \relatesalso polygon_90_concept + template <typename polygon_type, typename point_type> + typename enable_if< typename gtl_and< typename is_mutable_polygon_90_type<polygon_type>::type, + typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, + polygon_type>::type & + convolve(polygon_type& polygon, const point_type& point) { + std::vector<typename polygon_90_traits<polygon_type>::coordinate_type> coords; + coords.reserve(size(polygon)); + bool pingpong = true; + for(typename polygon_90_traits<polygon_type>::compact_iterator_type iter = begin_compact(polygon); + iter != end_compact(polygon); ++iter) { + coords.push_back((*iter) + (pingpong ? x(point) : y(point))); + pingpong = !pingpong; + } + polygon_90_mutable_traits<polygon_type>::set_compact(polygon, coords.begin(), coords.end()); + return polygon; + } + +/// \relatesalso polygon_concept + template <typename polygon_type, typename point_type> + typename enable_if< typename gtl_and< typename gtl_or< + typename is_mutable_polygon_45_type<polygon_type>::type, + typename is_mutable_polygon_type<polygon_type>::type>::type, + typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, + polygon_type>::type & + convolve(polygon_type& polygon, const point_type& point) { + std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + convolve(points.back(), point); + } + polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); + return polygon; + } + +/// \relatesalso polygon_with_holes_concept + template <typename polygon_type, typename point_type> + typename enable_if< + typename gtl_and< typename is_any_mutable_polygon_with_holes_type<polygon_type>::type, + typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, + polygon_type>::type & + convolve(polygon_type& polygon, const point_type& point) { + typedef typename polygon_with_holes_traits<polygon_type>::hole_type hole_type; + hole_type h; + set_points(h, begin_points(polygon), end_points(polygon)); + convolve(h, point); + std::vector<hole_type> holes; + holes.reserve(size_holes(polygon)); + for(typename polygon_with_holes_traits<polygon_type>::iterator_holes_type itr = begin_holes(polygon); + itr != end_holes(polygon); ++itr) { + holes.push_back(*itr); + convolve(holes.back(), point); + } + assign(polygon, h); + set_holes(polygon, holes.begin(), holes.end()); + return polygon; + } + +/// \relatesalso polygon_concept + template <typename T> + typename enable_if< typename is_any_mutable_polygon_type<T>::type, T>::type & + move(T& polygon, orientation_2d orient, typename polygon_traits<T>::coordinate_type displacement) { + typedef typename polygon_traits<T>::coordinate_type Unit; + if(orient == HORIZONTAL) return convolve(polygon, point_data<Unit>(displacement, Unit(0))); + return convolve(polygon, point_data<Unit>(Unit(0), displacement)); + } + +/// \relatesalso polygon_concept +/// \brief Applies a transformation to the polygon. +/// \tparam polygon_type A type that models polygon_concept +/// \tparam transform_type A type that may be either axis_transformation or transformation or that overloads point_concept::transform +/// \param polygon The polygon to transform +/// \param tr The transformation to apply + template <typename polygon_type, typename transform_type> + typename enable_if< typename is_any_mutable_polygon_without_holes_type<polygon_type>::type, polygon_type>::type & + transform(polygon_type& polygon, const transform_type& tr) { + std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + transform(points.back(), tr); + } + polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); + return polygon; + } + +/// \relatesalso polygon_with_holes_concept + template <typename T, typename transform_type> + typename enable_if< typename is_any_mutable_polygon_with_holes_type<T>::type, T>::type & + transform(T& polygon, const transform_type& tr) { + typedef typename polygon_with_holes_traits<T>::hole_type hole_type; + hole_type h; + set_points(h, begin_points(polygon), end_points(polygon)); + transform(h, tr); + std::vector<hole_type> holes; + holes.reserve(size_holes(polygon)); + for(typename polygon_with_holes_traits<T>::iterator_holes_type itr = begin_holes(polygon); + itr != end_holes(polygon); ++itr) { + holes.push_back(*itr); + transform(holes.back(), tr); + } + assign(polygon, h); + set_holes(polygon, holes.begin(), holes.end()); + return polygon; + } + + template <typename polygon_type> + typename enable_if< typename is_any_mutable_polygon_without_holes_type<polygon_type>::type, polygon_type>::type & + scale_up(polygon_type& polygon, typename coordinate_traits<typename polygon_traits<polygon_type>::coordinate_type>::unsigned_area_type factor) { + std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + scale_up(points.back(), factor); + } + polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); + return polygon; + } + + template <typename T> + typename enable_if< typename is_any_mutable_polygon_with_holes_type<T>::type, T>::type & + scale_up(T& polygon, typename coordinate_traits<typename polygon_traits<T>::coordinate_type>::unsigned_area_type factor) { + typedef typename polygon_with_holes_traits<T>::hole_type hole_type; + hole_type h; + set_points(h, begin_points(polygon), end_points(polygon)); + scale_up(h, factor); + std::vector<hole_type> holes; + holes.reserve(size_holes(polygon)); + for(typename polygon_with_holes_traits<T>::iterator_holes_type itr = begin_holes(polygon); + itr != end_holes(polygon); ++itr) { + holes.push_back(*itr); + scale_up(holes.back(), factor); + } + assign(polygon, h); + set_holes(polygon, holes.begin(), holes.end()); + return polygon; + } + + //scale non-45 down + template <typename polygon_type> + typename enable_if< + typename gtl_and< typename is_any_mutable_polygon_without_holes_type<polygon_type>::type, + typename gtl_not<typename gtl_same_type + < forty_five_domain, + typename geometry_domain<typename geometry_concept<polygon_type>::type>::type>::type>::type>::type, + polygon_type>::type & + scale_down(polygon_type& polygon, typename coordinate_traits<typename polygon_traits<polygon_type>::coordinate_type>::unsigned_area_type factor) { + std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + scale_down(points.back(), factor); + } + polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); + return polygon; + } + + template <typename Unit> + Unit local_abs(Unit value) { return value < 0 ? (Unit)-value : value; } + + template <typename Unit> + void snap_point_vector_to_45(std::vector<point_data<Unit> >& pts) { + typedef point_data<Unit> Point; + if(pts.size() < 3) { pts.clear(); return; } + Point firstPt = pts.front(); + Point prevPt = firstPt; + typename std::vector<point_data<Unit> >::iterator endLocation = std::unique(pts.begin(), pts.end()); + if(endLocation != pts.end()){ + pts.resize(endLocation - pts.begin()); + } + if(pts.back() == pts[0]) pts.pop_back(); + //iterate over point triplets + int numPts = pts.size(); + bool wrap_around = false; + for(int i = 0; i < numPts; ++i) { + Point& pt1 = pts[i]; + Point& pt2 = pts[(i + 1) % numPts]; + Point& pt3 = pts[(i + 2) % numPts]; + //check if non-45 edge + Unit deltax = x(pt2) - x(pt1); + Unit deltay = y(pt2) - y(pt1); + if(deltax && deltay && + local_abs(deltax) != local_abs(deltay)) { + //adjust the middle point + Unit ndx = x(pt3) - x(pt2); + Unit ndy = y(pt3) - y(pt2); + if(ndx && ndy) { + Unit diff = local_abs(local_abs(deltax) - local_abs(deltay)); + Unit halfdiff = diff/2; + if((deltax > 0 && deltay > 0) || + (deltax < 0 && deltay < 0)) { + //previous edge is rising slope + if(local_abs(deltax + halfdiff + (diff % 2)) == + local_abs(deltay - halfdiff)) { + x(pt2, x(pt2) + halfdiff + (diff % 2)); + y(pt2, y(pt2) - halfdiff); + } else if(local_abs(deltax - halfdiff - (diff % 2)) == + local_abs(deltay + halfdiff)) { + x(pt2, x(pt2) - halfdiff - (diff % 2)); + y(pt2, y(pt2) + halfdiff); + } else{ + //std::cout << "fail1\n"; + } + } else { + //previous edge is falling slope + if(local_abs(deltax + halfdiff + (diff % 2)) == + local_abs(deltay + halfdiff)) { + x(pt2, x(pt2) + halfdiff + (diff % 2)); + y(pt2, y(pt2) + halfdiff); + } else if(local_abs(deltax - halfdiff - (diff % 2)) == + local_abs(deltay - halfdiff)) { + x(pt2, x(pt2) - halfdiff - (diff % 2)); + y(pt2, y(pt2) - halfdiff); + } else { + //std::cout << "fail2\n"; + } + } + if(i == numPts - 1 && (diff % 2)) { + //we have a wrap around effect + if(!wrap_around) { + wrap_around = true; + i = -1; + } + } + } else if(ndx) { + //next edge is horizontal + //find the x value for pt1 that would make the abs(deltax) == abs(deltay) + Unit newDeltaX = local_abs(deltay); + if(deltax < 0) newDeltaX *= -1; + x(pt2, x(pt1) + newDeltaX); + } else { //ndy + //next edge is vertical + //find the y value for pt1 that would make the abs(deltax) == abs(deltay) + Unit newDeltaY = local_abs(deltax); + if(deltay < 0) newDeltaY *= -1; + y(pt2, y(pt1) + newDeltaY); + } + } + } + } + + template <typename polygon_type> + typename enable_if< typename is_any_mutable_polygon_without_holes_type<polygon_type>::type, polygon_type>::type & + snap_to_45(polygon_type& polygon) { + std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + } + snap_point_vector_to_45(points); + polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); + return polygon; + } + + template <typename polygon_type> + typename enable_if< typename is_any_mutable_polygon_with_holes_type<polygon_type>::type, polygon_type>::type & + snap_to_45(polygon_type& polygon) { + typedef typename polygon_with_holes_traits<polygon_type>::hole_type hole_type; + hole_type h; + set_points(h, begin_points(polygon), end_points(polygon)); + snap_to_45(h); + std::vector<hole_type> holes; + holes.reserve(size_holes(polygon)); + for(typename polygon_with_holes_traits<polygon_type>::iterator_holes_type itr = begin_holes(polygon); + itr != end_holes(polygon); ++itr) { + holes.push_back(*itr); + snap_to_45(holes.back()); + } + assign(polygon, h); + set_holes(polygon, holes.begin(), holes.end()); + return polygon; + } + + //scale specifically 45 down + template <typename polygon_type> + typename enable_if< + typename gtl_and< typename is_any_mutable_polygon_without_holes_type<polygon_type>::type, + typename gtl_same_type + < forty_five_domain, + typename geometry_domain<typename geometry_concept<polygon_type>::type>::type>::type>::type, + polygon_type>::type & + scale_down(polygon_type& polygon, typename coordinate_traits<typename polygon_traits<polygon_type>::coordinate_type>::unsigned_area_type factor) { + std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + scale_down(points.back(), factor); + } + snap_point_vector_to_45(points); + polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); + return polygon; + } + + template <typename T> + typename enable_if< typename is_any_mutable_polygon_with_holes_type<T>::type, T>::type & + scale_down(T& polygon, typename coordinate_traits<typename polygon_traits<T>::coordinate_type>::unsigned_area_type factor) { + typedef typename polygon_with_holes_traits<T>::hole_type hole_type; + hole_type h; + set_points(h, begin_points(polygon), end_points(polygon)); + scale_down(h, factor); + std::vector<hole_type> holes; + holes.reserve(size_holes(polygon)); + for(typename polygon_with_holes_traits<T>::iterator_holes_type itr = begin_holes(polygon); + itr != end_holes(polygon); ++itr) { + holes.push_back(*itr); + scale_down(holes.back(), factor); + } + assign(polygon, h); + set_holes(polygon, holes.begin(), holes.end()); + return polygon; + } + + //scale non-45 + template <typename polygon_type> + typename enable_if< + typename gtl_and< typename is_any_mutable_polygon_without_holes_type<polygon_type>::type, + typename gtl_not<typename gtl_same_type + < forty_five_domain, + typename geometry_domain<typename geometry_concept<polygon_type>::type>::type>::type>::type>::type, + polygon_type>::type & + scale(polygon_type& polygon, double factor) { + std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + scale(points.back(), anisotropic_scale_factor<double>(factor, factor)); + } + polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); + return polygon; + } + + //scale specifically 45 + template <typename polygon_type> + polygon_type& + scale(polygon_type& polygon, double factor, + typename enable_if< + typename gtl_and< typename is_any_mutable_polygon_without_holes_type<polygon_type>::type, + typename gtl_same_type + < forty_five_domain, + typename geometry_domain<typename geometry_concept<polygon_type>::type>::type>::type>::type>::type * = 0 + ) { + std::vector<typename std::iterator_traits<typename polygon_traits<polygon_type>::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits<polygon_type>::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + scale(points.back(), anisotropic_scale_factor<double>(factor, factor)); + } + snap_point_vector_to_45(points); + polygon_mutable_traits<polygon_type>::set_points(polygon, points.begin(), points.end()); + return polygon; + } + + template <typename T> + T& + scale(T& polygon, double factor, + typename enable_if< typename is_any_mutable_polygon_with_holes_type<T>::type>::type * = 0 + ) { + typedef typename polygon_with_holes_traits<T>::hole_type hole_type; + hole_type h; + set_points(h, begin_points(polygon), end_points(polygon)); + scale(h, factor); + std::vector<hole_type> holes; + holes.reserve(size_holes(polygon)); + for(typename polygon_with_holes_traits<T>::iterator_holes_type itr = begin_holes(polygon); + itr != end_holes(polygon); ++itr) { + holes.push_back(*itr); + scale(holes.back(), factor); + } + assign(polygon, h); + set_holes(polygon, holes.begin(), holes.end()); + return polygon; + } + + template <typename iterator_type, typename area_type> + static area_type + point_sequence_area(iterator_type begin_range, iterator_type end_range) { + typedef typename std::iterator_traits<iterator_type>::value_type point_type; + typedef typename point_traits<point_type>::coordinate_type Unit; + if(begin_range == end_range) return area_type(0); + point_type first = *begin_range; + point_type previous = first; + ++begin_range; + // Initialize trapezoid base line + area_type y_base = (area_type)y(first); + // Initialize area accumulator + + area_type area(0); + while (begin_range != end_range) { + area_type x1 = (area_type)x(previous); + area_type x2 = (area_type)x(*begin_range); +#ifdef BOOST_POLYGON_ICC +#pragma warning (disable:1572) +#endif + if(x1 != x2) { +#ifdef BOOST_POLYGON_ICC +#pragma warning (default:1572) +#endif + // do trapezoid area accumulation + area += (x2 - x1) * (((area_type)y(*begin_range) - y_base) + + ((area_type)y(previous) - y_base)) / 2; + } + previous = *begin_range; + // go to next point + ++begin_range; + } + //wrap around to evaluate the edge between first and last if not closed + if(!equivalence(first, previous)) { + area_type x1 = (area_type)x(previous); + area_type x2 = (area_type)x(first); + area += (x2 - x1) * (((area_type)y(first) - y_base) + + ((area_type)y(previous) - y_base)) / 2; + } + return area; + } + + template <typename T> + typename enable_if< + typename is_polygon_with_holes_type<T>::type, + typename area_type_by_domain< typename geometry_domain<typename geometry_concept<T>::type>::type, + typename polygon_traits<T>::coordinate_type>::type>::type + area(const T& polygon) { + typedef typename area_type_by_domain< typename geometry_domain<typename geometry_concept<T>::type>::type, + typename polygon_traits<T>::coordinate_type>::type area_type; + area_type retval = point_sequence_area<typename polygon_traits<T>::iterator_type, area_type> + (begin_points(polygon), end_points(polygon)); + if(retval < 0) retval *= -1; + for(typename polygon_with_holes_traits<T>::iterator_holes_type itr = + polygon_with_holes_traits<T>::begin_holes(polygon); + itr != polygon_with_holes_traits<T>::end_holes(polygon); ++itr) { + area_type tmp_area = point_sequence_area + <typename polygon_traits<typename polygon_with_holes_traits<T>::hole_type>::iterator_type, area_type> + (begin_points(*itr), end_points(*itr)); + if(tmp_area < 0) tmp_area *= -1; + retval -= tmp_area; + } + return retval; + } + + template <typename iT> + bool point_sequence_is_45(iT itr, iT itr_end) { + typedef typename iT::value_type Point; + typedef typename point_traits<Point>::coordinate_type Unit; + if(itr == itr_end) return true; + Point firstPt = *itr; + Point prevPt = firstPt; + ++itr; + while(itr != itr_end) { + Point pt = *itr; + Unit deltax = x(pt) - x(prevPt); + Unit deltay = y(pt) - y(prevPt); + if(deltax && deltay && + local_abs(deltax) != local_abs(deltay)) + return false; + prevPt = pt; + ++itr; + } + Unit deltax = x(firstPt) - x(prevPt); + Unit deltay = y(firstPt) - y(prevPt); + if(deltax && deltay && + local_abs(deltax) != local_abs(deltay)) + return false; + return true; + } + + template <typename polygon_type> + typename enable_if< typename is_polygon_with_holes_type<polygon_type>::type, bool>::type + is_45(const polygon_type& polygon) { + typename polygon_traits<polygon_type>::iterator_type itr = begin_points(polygon), itr_end = end_points(polygon); + if(!point_sequence_is_45(itr, itr_end)) return false; + typename polygon_with_holes_traits<polygon_type>::iterator_holes_type itrh = begin_holes(polygon), itrh_end = end_holes(polygon); + typedef typename polygon_with_holes_traits<polygon_type>::hole_type hole_type; + for(; itrh != itrh_end; ++ itrh) { + typename polygon_traits<hole_type>::iterator_type itr1 = begin_points(polygon), itr1_end = end_points(polygon); + if(!point_sequence_is_45(itr1, itr1_end)) return false; + } + return true; + } + + template <typename distance_type, typename iterator_type> + distance_type point_sequence_distance(iterator_type itr, iterator_type itr_end) { + typedef distance_type Unit; + typedef iterator_type iterator; + typedef typename std::iterator_traits<iterator>::value_type point_type; + Unit return_value = Unit(0); + point_type previous_point, first_point; + if(itr == itr_end) return return_value; + previous_point = first_point = *itr; + ++itr; + for( ; itr != itr_end; ++itr) { + point_type current_point = *itr; + return_value += (Unit)euclidean_distance(current_point, previous_point); + previous_point = current_point; + } + return_value += (Unit)euclidean_distance(previous_point, first_point); + return return_value; + } + + template <typename T> + typename distance_type_by_domain + <typename geometry_domain<typename geometry_concept<T>::type>::type, typename polygon_traits<T>::coordinate_type>::type + perimeter(const T& polygon, + typename enable_if< + typename is_polygon_with_holes_type<T>::type>::type * = 0 + ) { + typedef typename distance_type_by_domain + <typename geometry_domain<typename geometry_concept<T>::type>::type, typename polygon_traits<T>::coordinate_type>::type Unit; + typedef typename polygon_traits<T>::iterator_type iterator; + iterator itr = begin_points(polygon); + iterator itr_end = end_points(polygon); + Unit return_value = point_sequence_distance<Unit, iterator>(itr, itr_end); + for(typename polygon_with_holes_traits<T>::iterator_holes_type itr_holes = begin_holes(polygon); + itr_holes != end_holes(polygon); ++itr_holes) { + typedef typename polygon_traits<typename polygon_with_holes_traits<T>::hole_type>::iterator_type hitertype; + return_value += point_sequence_distance<Unit, hitertype>(begin_points(*itr_holes), end_points(*itr_holes)); + } + return return_value; + } + + template <typename T> + typename enable_if <typename is_polygon_with_holes_type<T>::type, + direction_1d>::type + winding(const T& polygon) { + winding_direction wd = polygon_traits<T>::winding(polygon); + if(wd != unknown_winding) { + return wd == clockwise_winding ? CLOCKWISE: COUNTERCLOCKWISE; + } + typedef typename area_type_by_domain< typename geometry_domain<typename geometry_concept<T>::type>::type, + typename polygon_traits<T>::coordinate_type>::type area_type; + return point_sequence_area<typename polygon_traits<T>::iterator_type, area_type>(begin_points(polygon), end_points(polygon)) < 0 ? + COUNTERCLOCKWISE : CLOCKWISE; + } + + template <typename T, typename input_point_type> + typename enable_if< + typename gtl_and< typename is_polygon_90_type<T>::type, + typename gtl_same_type<typename geometry_concept<input_point_type>::type, point_concept>::type>::type, + bool>::type + contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { + typedef T polygon_type; + typedef typename polygon_traits<polygon_type>::coordinate_type coordinate_type; + typedef typename polygon_traits<polygon_type>::iterator_type iterator; + typedef typename std::iterator_traits<iterator>::value_type point_type; + iterator iter, iter_end; + iter_end = end_points(polygon); + iter = begin_points(polygon); + point_type prev_pt = *iter; + std::size_t num = size(polygon); + std::size_t counts[2] = {0, 0}; + for(std::size_t i = 0; i < num; ++i) { + if(i == num-1) iter = begin_points(polygon); + else ++iter; + point_type current_pt = *iter; + if(x(current_pt) == + x(prev_pt)) { + unsigned int index = x(current_pt) > + x(point); + std::size_t increment = 0; + interval_data<coordinate_type> ivl(y(current_pt), + y(prev_pt)); + if(contains(ivl, y(point), true)) { + if(x(current_pt) == + x(point)) return consider_touch; + ++increment; + if(y(current_pt) != + y(point) && + y(prev_pt) != + y(point)) { + ++increment; + } + counts[index] += increment; + } + } + prev_pt = current_pt; + } + //odd count implies boundary condition + if(counts[0] % 2 || counts[1] % 2) return consider_touch; + //an odd number of edges to the left implies interior pt + return counts[winding(polygon) == COUNTERCLOCKWISE ? 0 : 1] % 4 != 0; + } + + //TODO: refactor to expose as user APIs + template <typename Unit> + struct edge_utils { + typedef point_data<Unit> Point; + typedef std::pair<Point, Point> half_edge; + + class less_point : public std::binary_function<Point, Point, bool> { + public: + inline less_point() {} + inline bool operator () (const Point& pt1, const Point& pt2) const { + if(pt1.get(HORIZONTAL) < pt2.get(HORIZONTAL)) return true; + if(pt1.get(HORIZONTAL) == pt2.get(HORIZONTAL)) { + if(pt1.get(VERTICAL) < pt2.get(VERTICAL)) return true; + } + return false; + } + }; + + static inline bool between(Point pt, Point pt1, Point pt2) { + less_point lp; + if(lp(pt1, pt2)) + return lp(pt, pt2) && lp(pt1, pt); + return lp(pt, pt1) && lp(pt2, pt); + } + + template <typename area_type> + static inline bool equal_slope(area_type dx1, area_type dy1, area_type dx2, area_type dy2) { + typedef typename coordinate_traits<Unit>::unsigned_area_type unsigned_product_type; + unsigned_product_type cross_1 = (unsigned_product_type)(dx2 < 0 ? -dx2 :dx2) * (unsigned_product_type)(dy1 < 0 ? -dy1 : dy1); + unsigned_product_type cross_2 = (unsigned_product_type)(dx1 < 0 ? -dx1 :dx1) * (unsigned_product_type)(dy2 < 0 ? -dy2 : dy2); + int dx1_sign = dx1 < 0 ? -1 : 1; + int dx2_sign = dx2 < 0 ? -1 : 1; + int dy1_sign = dy1 < 0 ? -1 : 1; + int dy2_sign = dy2 < 0 ? -1 : 1; + int cross_1_sign = dx2_sign * dy1_sign; + int cross_2_sign = dx1_sign * dy2_sign; + return cross_1 == cross_2 && (cross_1_sign == cross_2_sign || cross_1 == 0); + } + + static inline bool equal_slope(const Unit& x, const Unit& y, + const Point& pt1, const Point& pt2) { + const Point* pts[2] = {&pt1, &pt2}; + typedef typename coordinate_traits<Unit>::manhattan_area_type at; + at dy2 = (at)pts[1]->get(VERTICAL) - (at)y; + at dy1 = (at)pts[0]->get(VERTICAL) - (at)y; + at dx2 = (at)pts[1]->get(HORIZONTAL) - (at)x; + at dx1 = (at)pts[0]->get(HORIZONTAL) - (at)x; + return equal_slope(dx1, dy1, dx2, dy2); + } + + template <typename area_type> + static inline bool less_slope(area_type dx1, area_type dy1, area_type dx2, area_type dy2) { + //reflext x and y slopes to right hand side half plane + if(dx1 < 0) { + dy1 *= -1; + dx1 *= -1; + } else if(dx1 == 0) { + //if the first slope is vertical the first cannot be less + return false; + } + if(dx2 < 0) { + dy2 *= -1; + dx2 *= -1; + } else if(dx2 == 0) { + //if the second slope is vertical the first is always less unless it is also vertical, in which case they are equal + return dx1 != 0; + } + typedef typename coordinate_traits<Unit>::unsigned_area_type unsigned_product_type; + unsigned_product_type cross_1 = (unsigned_product_type)(dx2 < 0 ? -dx2 :dx2) * (unsigned_product_type)(dy1 < 0 ? -dy1 : dy1); + unsigned_product_type cross_2 = (unsigned_product_type)(dx1 < 0 ? -dx1 :dx1) * (unsigned_product_type)(dy2 < 0 ? -dy2 : dy2); + int dx1_sign = dx1 < 0 ? -1 : 1; + int dx2_sign = dx2 < 0 ? -1 : 1; + int dy1_sign = dy1 < 0 ? -1 : 1; + int dy2_sign = dy2 < 0 ? -1 : 1; + int cross_1_sign = dx2_sign * dy1_sign; + int cross_2_sign = dx1_sign * dy2_sign; + if(cross_1_sign < cross_2_sign) return true; + if(cross_2_sign < cross_1_sign) return false; + if(cross_1_sign == -1) return cross_2 < cross_1; + return cross_1 < cross_2; + } + + static inline bool less_slope(const Unit& x, const Unit& y, + const Point& pt1, const Point& pt2) { + const Point* pts[2] = {&pt1, &pt2}; + //compute y value on edge from pt_ to pts[1] at the x value of pts[0] + typedef typename coordinate_traits<Unit>::manhattan_area_type at; + at dy2 = (at)pts[1]->get(VERTICAL) - (at)y; + at dy1 = (at)pts[0]->get(VERTICAL) - (at)y; + at dx2 = (at)pts[1]->get(HORIZONTAL) - (at)x; + at dx1 = (at)pts[0]->get(HORIZONTAL) - (at)x; + return less_slope(dx1, dy1, dx2, dy2); + } + + //return -1 below, 0 on and 1 above line + //assumes point is on x interval of segment + static inline int on_above_or_below(Point pt, const half_edge& he) { + if(pt == he.first || pt == he.second) return 0; + if(equal_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), he.first, he.second)) return 0; + bool less_result = less_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), he.first, he.second); + int retval = less_result ? -1 : 1; + less_point lp; + if(lp(he.second, he.first)) retval *= -1; + if(!between(pt, he.first, he.second)) retval *= -1; + return retval; + } + }; + + template <typename T, typename input_point_type> + typename enable_if< + typename gtl_and< typename is_any_mutable_polygon_with_holes_type<T>::type, + typename gtl_same_type<typename geometry_concept<input_point_type>::type, point_concept>::type>::type, + bool>::type + contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { + typedef typename polygon_with_holes_traits<T>::iterator_holes_type holes_iterator; + bool isInside = contains( view_as< typename polygon_from_polygon_with_holes_type< + typename geometry_concept<T>::type>::type>( polygon ), point, consider_touch ); + if(!isInside) return false; //no need to check holes + holes_iterator itH = begin_holes( polygon ); + while( itH != end_holes( polygon ) ) { + if( contains( *itH, point, !consider_touch ) ) { + isInside = false; + break; + } + ++itH; + } + return isInside; + } + + template <typename T, typename input_point_type> + typename enable_if< + typename gtl_and_3< + typename is_polygon_type<T>::type, + typename gtl_different_type<typename geometry_domain<typename geometry_concept<T>::type>::type, manhattan_domain>::type, + typename gtl_same_type<typename geometry_concept<input_point_type>::type, point_concept>::type>::type, + bool>::type + contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { + typedef typename point_traits<input_point_type>::coordinate_type Unit; + typedef point_data<Unit> Point; + typedef std::pair<Point, Point> half_edge; + typedef typename polygon_traits<T>::iterator_type iterator; + iterator itr = begin_points(polygon); + iterator itrEnd = end_points(polygon); + half_edge he; + if(itr == itrEnd) return false; + assign(he.first, *itr); + Point firstPt; + assign(firstPt, *itr); + ++itr; + if(itr == itrEnd) return false; + bool done = false; + int above = 0; + while(!done) { + Point currentPt; + if(itr == itrEnd) { + done = true; + currentPt = firstPt; + } else { + assign(currentPt, *itr); + ++itr; + } + if(currentPt == he.first) { + continue; + } else { + he.second = currentPt; + if(equivalence(point, currentPt)) return consider_touch; + Unit xmin = (std::min)(x(he.first), x(he.second)); + Unit xmax = (std::max)(x(he.first), x(he.second)); + if(x(point) >= xmin && x(point) < xmax) { //double counts if <= xmax + Point tmppt; + assign(tmppt, point); + int oabedge = edge_utils<Unit>::on_above_or_below(tmppt, he); + if(oabedge == 0) return consider_touch; + if(oabedge == 1) ++above; + } else if(x(point) == xmax) { + if(x(point) == xmin) { + Unit ymin = (std::min)(y(he.first), y(he.second)); + Unit ymax = (std::max)(y(he.first), y(he.second)); + Unit ypt = y(point); + if(ypt <= ymax && ypt >= ymin) + return consider_touch; + } else { + Point tmppt; + assign(tmppt, point); + if( edge_utils<Unit>::on_above_or_below(tmppt, he) == 0 ) { + return consider_touch; + } + } + } + } + he.first = he.second; + } + return above % 2 != 0; //if the point is above an odd number of edges is must be inside polygon + } + + /* + template <typename T, typename input_point_type> + typename enable_if< + typename gtl_and_3< + typename is_polygon_with_holes_type<T>::type, + typename gtl_different_type<typename geometry_domain<typename geometry_concept<T>::type>::type, manhattan_domain>::type, + typename gtl_same_type<typename geometry_concept<input_point_type>::type, point_concept>::type>::type, + bool>::type + contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { + typedef typename point_traits<input_point_type>::coordinate_type Unit; + typedef point_data<Unit> Point; + typedef std::pair<Point, Point> half_edge; + typedef typename polygon_traits<T>::iterator_type iterator; + iterator itr = begin_points(polygon); + iterator itrEnd = end_points(polygon); + half_edge he; + if(itr == itrEnd) return false; + assign(he.first, *itr); + Point firstPt; + assign(firstPt, *itr); + ++itr; + if(itr == itrEnd) return false; + bool done = false; + int above = 0; + while(!done) { + Point currentPt; + if(itr == itrEnd) { + done = true; + currentPt = firstPt; + } else { + assign(currentPt, *itr); + ++itr; + } + if(currentPt == he.first) { + continue; + } else { + he.second = currentPt; + if(equivalence(point, currentPt)) return consider_touch; + Unit xmin = (std::min)(x(he.first), x(he.second)); + Unit xmax = (std::max)(x(he.first), x(he.second)); + if(x(point) >= xmin && x(point) < xmax) { //double counts if <= xmax + Point tmppt; + assign(tmppt, point); + int oabedge = edge_utils<Unit>::on_above_or_below(tmppt, he); + if(oabedge == 0) return consider_touch; + if(oabedge == 1) ++above; + } + } + he.first = he.second; + } + return above % 2 != 0; //if the point is above an odd number of edges is must be inside polygon + } + */ + + template <typename T1, typename T2> + typename enable_if< + typename gtl_and< typename is_mutable_point_concept<typename geometry_concept<T1>::type>::type, + typename is_polygon_with_holes_type<T2>::type>::type, + bool>::type + center(T1& center_point, const T2& polygon) { + typedef typename polygon_traits<T2>::coordinate_type coordinate_type; + rectangle_data<coordinate_type> bbox; + extents(bbox, polygon); + return center(center_point, bbox); + } + + template <typename T1, typename T2> + typename enable_if< + typename gtl_and< typename is_mutable_rectangle_concept<typename geometry_concept<T1>::type>::type, + typename is_polygon_with_holes_type<T2>::type>::type, + bool>::type + extents(T1& bounding_box, const T2& polygon) { + typedef typename polygon_traits<T2>::iterator_type iterator; + bool first_iteration = true; + iterator itr_end = end_points(polygon); + for(iterator itr = begin_points(polygon); itr != itr_end; ++itr) { + if(first_iteration) { + set_points(bounding_box, *itr, *itr); + first_iteration = false; + } else { + encompass(bounding_box, *itr); + } + } + if(first_iteration) return false; + return true; + } + + template <class T> + template <class T2> + polygon_90_data<T>& polygon_90_data<T>::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template <class T> + template <class T2> + polygon_45_data<T>& polygon_45_data<T>::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template <class T> + template <class T2> + polygon_data<T>& polygon_data<T>::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template <class T> + template <class T2> + polygon_90_with_holes_data<T>& polygon_90_with_holes_data<T>::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template <class T> + template <class T2> + polygon_45_with_holes_data<T>& polygon_45_with_holes_data<T>::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template <class T> + template <class T2> + polygon_with_holes_data<T>& polygon_with_holes_data<T>::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template <typename T> + struct geometry_concept<polygon_data<T> > { + typedef polygon_concept type; + }; + template <typename T> + struct geometry_concept<polygon_45_data<T> > { + typedef polygon_45_concept type; + }; + template <typename T> + struct geometry_concept<polygon_90_data<T> > { + typedef polygon_90_concept type; + }; + template <typename T> + struct geometry_concept<polygon_with_holes_data<T> > { + typedef polygon_with_holes_concept type; + }; + template <typename T> + struct geometry_concept<polygon_45_with_holes_data<T> > { + typedef polygon_45_with_holes_concept type; + }; + template <typename T> + struct geometry_concept<polygon_90_with_holes_data<T> > { + typedef polygon_90_with_holes_concept type; + }; + +// template <typename T> struct polygon_with_holes_traits<polygon_90_data<T> > { +// typedef polygon_90_data<T> hole_type; +// typedef const hole_type* iterator_holes_type; +// static inline iterator_holes_type begin_holes(const hole_type& t) { return &t; } +// static inline iterator_holes_type end_holes(const hole_type& t) { return &t; } +// static inline std::size_t size_holes(const hole_type& t) { return 0; } +// }; +// template <typename T> struct polygon_with_holes_traits<polygon_45_data<T> > { +// typedef polygon_45_data<T> hole_type; +// typedef const hole_type* iterator_holes_type; +// static inline iterator_holes_type begin_holes(const hole_type& t) { return &t; } +// static inline iterator_holes_type end_holes(const hole_type& t) { return &t; } +// static inline std::size_t size_holes(const hole_type& t) { return 0; } +// }; +// template <typename T> struct polygon_with_holes_traits<polygon_data<T> > { +// typedef polygon_data<T> hole_type; +// typedef const hole_type* iterator_holes_type; +// static inline iterator_holes_type begin_holes(const hole_type& t) { return &t; } +// static inline iterator_holes_type end_holes(const hole_type& t) { return &t; } +// static inline std::size_t size_holes(const hole_type& t) { return 0; } +// }; + template <typename T> struct get_void {}; + template <> struct get_void<gtl_yes> { typedef void type; }; + + template <typename T> struct polygon_with_holes_traits< + T, typename get_void<typename is_any_mutable_polygon_without_holes_type<T>::type>::type > { + typedef T hole_type; + typedef const hole_type* iterator_holes_type; + static inline iterator_holes_type begin_holes(const hole_type& t) { return &t; } + static inline iterator_holes_type end_holes(const hole_type& t) { return &t; } + static inline std::size_t size_holes(const hole_type& t) { return 0; } + }; + + template <typename T> + struct view_of<rectangle_concept, T> { + typedef typename polygon_traits<T>::coordinate_type coordinate_type; + typedef interval_data<coordinate_type> interval_type; + rectangle_data<coordinate_type> rect; + view_of(const T& obj) : rect() { + point_data<coordinate_type> pts[2]; + typename polygon_traits<T>::iterator_type itr = + begin_points(obj), itre = end_points(obj); + if(itr == itre) return; + assign(pts[0], *itr); + ++itr; + if(itr == itre) return; + ++itr; + if(itr == itre) return; + assign(pts[1], *itr); + set_points(rect, pts[0], pts[1]); + } + inline interval_type get(orientation_2d orient) const { + return rect.get(orient); } + }; + + template <typename T> + struct geometry_concept<view_of<rectangle_concept, T> > { + typedef rectangle_concept type; + }; + + template <typename T> + struct view_of<polygon_45_concept, T> { + const T* t; + view_of(const T& obj) : t(&obj) {} + typedef typename polygon_traits<T>::coordinate_type coordinate_type; + typedef typename polygon_traits<T>::iterator_type iterator_type; + typedef typename polygon_traits<T>::point_type point_type; + + /// Get the begin iterator + inline iterator_type begin() const { + return polygon_traits<T>::begin_points(*t); + } + + /// Get the end iterator + inline iterator_type end() const { + return polygon_traits<T>::end_points(*t); + } + + /// Get the number of sides of the polygon + inline std::size_t size() const { + return polygon_traits<T>::size(*t); + } + + /// Get the winding direction of the polygon + inline winding_direction winding() const { + return polygon_traits<T>::winding(*t); + } + }; + + template <typename T> + struct geometry_concept<view_of<polygon_45_concept, T> > { + typedef polygon_45_concept type; + }; + + template <typename T> + struct view_of<polygon_90_concept, T> { + const T* t; + view_of(const T& obj) : t(&obj) {} + typedef typename polygon_traits<T>::coordinate_type coordinate_type; + typedef typename polygon_traits<T>::iterator_type iterator_type; + typedef typename polygon_traits<T>::point_type point_type; + typedef iterator_points_to_compact<iterator_type, point_type> compact_iterator_type; + + /// Get the begin iterator + inline compact_iterator_type begin_compact() const { + return compact_iterator_type(polygon_traits<T>::begin_points(*t), + polygon_traits<T>::end_points(*t)); + } + + /// Get the end iterator + inline compact_iterator_type end_compact() const { + return compact_iterator_type(polygon_traits<T>::end_points(*t), + polygon_traits<T>::end_points(*t)); + } + + /// Get the number of sides of the polygon + inline std::size_t size() const { + return polygon_traits<T>::size(*t); + } + + /// Get the winding direction of the polygon + inline winding_direction winding() const { + return polygon_traits<T>::winding(*t); + } + }; + + template <typename T> + struct geometry_concept<view_of<polygon_90_concept, T> > { + typedef polygon_90_concept type; + }; + + template <typename T> + struct view_of<polygon_45_with_holes_concept, T> { + const T* t; + view_of(const T& obj) : t(&obj) {} + typedef typename polygon_traits<T>::coordinate_type coordinate_type; + typedef typename polygon_traits<T>::iterator_type iterator_type; + typedef typename polygon_traits<T>::point_type point_type; + typedef view_of<polygon_45_concept, typename polygon_with_holes_traits<T>::hole_type> hole_type; + struct iterator_holes_type { + typedef std::forward_iterator_tag iterator_category; + typedef hole_type value_type; + typedef std::ptrdiff_t difference_type; + typedef const hole_type* pointer; //immutable + typedef const hole_type& reference; //immutable + typedef typename polygon_with_holes_traits<T>::iterator_holes_type iht; + iht internal_itr; + iterator_holes_type() : internal_itr() {} + iterator_holes_type(iht iht_in) : internal_itr(iht_in) {} + inline iterator_holes_type& operator++() { + ++internal_itr; + return *this; + } + inline const iterator_holes_type operator++(int) { + iterator_holes_type tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator_holes_type& that) const { + return (internal_itr == that.internal_itr); + } + inline bool operator!=(const iterator_holes_type& that) const { + return (internal_itr != that.internal_itr); + } + inline value_type operator*() const { + return view_as<polygon_45_concept>(*internal_itr); + } + }; + + /// Get the begin iterator + inline iterator_type begin() const { + return polygon_traits<T>::begin_points(*t); + } + + /// Get the end iterator + inline iterator_type end() const { + return polygon_traits<T>::end_points(*t); + } + + /// Get the number of sides of the polygon + inline std::size_t size() const { + return polygon_traits<T>::size(*t); + } + + /// Get the winding direction of the polygon + inline winding_direction winding() const { + return polygon_traits<T>::winding(*t); + } + + /// Get the begin iterator + inline iterator_holes_type begin_holes() const { + return polygon_with_holes_traits<T>::begin_holes(*t); + } + + /// Get the end iterator + inline iterator_holes_type end_holes() const { + return polygon_with_holes_traits<T>::end_holes(*t); + } + + /// Get the number of sides of the polygon + inline std::size_t size_holes() const { + return polygon_with_holes_traits<T>::size_holes(*t); + } + + }; + + template <typename T> + struct geometry_concept<view_of<polygon_45_with_holes_concept, T> > { + typedef polygon_45_with_holes_concept type; + }; + + template <typename T> + struct view_of<polygon_90_with_holes_concept, T> { + const T* t; + view_of(const T& obj) : t(&obj) {} + typedef typename polygon_traits<T>::coordinate_type coordinate_type; + typedef typename polygon_traits<T>::iterator_type iterator_type; + typedef typename polygon_traits<T>::point_type point_type; + typedef iterator_points_to_compact<iterator_type, point_type> compact_iterator_type; + typedef view_of<polygon_90_concept, typename polygon_with_holes_traits<T>::hole_type> hole_type; + struct iterator_holes_type { + typedef std::forward_iterator_tag iterator_category; + typedef hole_type value_type; + typedef std::ptrdiff_t difference_type; + typedef const hole_type* pointer; //immutable + typedef const hole_type& reference; //immutable + typedef typename polygon_with_holes_traits<T>::iterator_holes_type iht; + iht internal_itr; + iterator_holes_type() : internal_itr() {} + iterator_holes_type(iht iht_in) : internal_itr(iht_in) {} + inline iterator_holes_type& operator++() { + ++internal_itr; + return *this; + } + inline const iterator_holes_type operator++(int) { + iterator_holes_type tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator_holes_type& that) const { + return (internal_itr == that.internal_itr); + } + inline bool operator!=(const iterator_holes_type& that) const { + return (internal_itr != that.internal_itr); + } + inline value_type operator*() const { + return view_as<polygon_90_concept>(*internal_itr); + } + }; + + /// Get the begin iterator + inline compact_iterator_type begin_compact() const { + return compact_iterator_type(polygon_traits<T>::begin_points(*t), + polygon_traits<T>::end_points(*t)); + } + + /// Get the end iterator + inline compact_iterator_type end_compact() const { + return compact_iterator_type(polygon_traits<T>::end_points(*t), + polygon_traits<T>::end_points(*t)); + } + + /// Get the number of sides of the polygon + inline std::size_t size() const { + return polygon_traits<T>::size(*t); + } + + /// Get the winding direction of the polygon + inline winding_direction winding() const { + return polygon_traits<T>::winding(*t); + } + + /// Get the begin iterator + inline iterator_holes_type begin_holes() const { + return polygon_with_holes_traits<T>::begin_holes(*t); + } + + /// Get the end iterator + inline iterator_holes_type end_holes() const { + return polygon_with_holes_traits<T>::end_holes(*t); + } + + /// Get the number of sides of the polygon + inline std::size_t size_holes() const { + return polygon_with_holes_traits<T>::size_holes(*t); + } + + }; + + template <typename T> + struct geometry_concept<view_of<polygon_90_with_holes_concept, T> > { + typedef polygon_90_with_holes_concept type; + }; + + template <typename T> + struct view_of<polygon_concept, T> { + const T* t; + view_of(const T& obj) : t(&obj) {} + typedef typename polygon_traits<T>::coordinate_type coordinate_type; + typedef typename polygon_traits<T>::iterator_type iterator_type; + typedef typename polygon_traits<T>::point_type point_type; + + /// Get the begin iterator + inline iterator_type begin() const { + return polygon_traits<T>::begin_points(*t); + } + + /// Get the end iterator + inline iterator_type end() const { + return polygon_traits<T>::end_points(*t); + } + + /// Get the number of sides of the polygon + inline std::size_t size() const { + return polygon_traits<T>::size(*t); + } + + /// Get the winding direction of the polygon + inline winding_direction winding() const { + return polygon_traits<T>::winding(*t); + } + }; + + template <typename T> + struct geometry_concept<view_of<polygon_concept, T> > { + typedef polygon_concept type; + }; +} +} + +#endif + diff --git a/boost/polygon/polygon_with_holes_data.hpp b/boost/polygon/polygon_with_holes_data.hpp new file mode 100644 index 0000000000..e5a975bbdf --- /dev/null +++ b/boost/polygon/polygon_with_holes_data.hpp @@ -0,0 +1,108 @@ +/* + 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_POLYGON_WITH_HOLES_DATA_HPP +#define BOOST_POLYGON_POLYGON_WITH_HOLES_DATA_HPP +#include "isotropy.hpp" +#include "polygon_data.hpp" +namespace boost { namespace polygon{ + struct polygon_with_holes_concept; + template <typename T> + class polygon_with_holes_data { +public: + typedef polygon_with_holes_concept geometry_type; + typedef T coordinate_type; + typedef typename polygon_data<T>::iterator_type iterator_type; + typedef typename std::list<polygon_data<coordinate_type> >::const_iterator iterator_holes_type; + typedef polygon_data<coordinate_type> hole_type; + typedef typename coordinate_traits<T>::coordinate_distance area_type; + typedef point_data<T> point_type; + + // default constructor of point does not initialize x and y + inline polygon_with_holes_data() : self_(), holes_() {} //do nothing default constructor + + template<class iT> + inline polygon_with_holes_data(iT input_begin, iT input_end) : self_(), holes_() { + set(input_begin, input_end); + } + + template<class iT, typename hiT> + inline polygon_with_holes_data(iT input_begin, iT input_end, hiT holes_begin, hiT holes_end) : self_(), holes_() { + set(input_begin, input_end); + set_holes(holes_begin, holes_end); + } + + template<class iT> + inline polygon_with_holes_data& set(iT input_begin, iT input_end) { + self_.set(input_begin, input_end); + return *this; + } + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template<class iT> + inline polygon_with_holes_data& set_holes(iT input_begin, iT input_end) { + holes_.clear(); //just in case there was some old data there + for( ; input_begin != input_end; ++ input_begin) { + holes_.push_back(hole_type()); + holes_.back().set((*input_begin).begin(), (*input_begin).end()); + } + return *this; + } + + // copy constructor (since we have dynamic memory) + inline polygon_with_holes_data(const polygon_with_holes_data& that) : self_(that.self_), + holes_(that.holes_) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline polygon_with_holes_data& operator=(const polygon_with_holes_data& that) { + self_ = that.self_; + holes_ = that.holes_; + return *this; + } + + template <typename T2> + inline polygon_with_holes_data& operator=(const T2& rvalue); + + // get begin iterator, returns a pointer to a const coordinate_type + inline const iterator_type begin() const { + return self_.begin(); + } + + // get end iterator, returns a pointer to a const coordinate_type + inline const iterator_type end() const { + return self_.end(); + } + + inline std::size_t size() const { + return self_.size(); + } + + // get begin iterator, returns a pointer to a const polygon + inline const iterator_holes_type begin_holes() const { + return holes_.begin(); + } + + // get end iterator, returns a pointer to a const polygon + inline const iterator_holes_type end_holes() const { + return holes_.end(); + } + + inline std::size_t size_holes() const { + return holes_.size(); + } + +public: + polygon_data<coordinate_type> self_; + std::list<hole_type> holes_; + }; + + +} +} +#endif + diff --git a/boost/polygon/rectangle_concept.hpp b/boost/polygon/rectangle_concept.hpp new file mode 100644 index 0000000000..e302b99c90 --- /dev/null +++ b/boost/polygon/rectangle_concept.hpp @@ -0,0 +1,1080 @@ +/* + 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_RECTANGLE_CONCEPT_HPP +#define BOOST_POLYGON_RECTANGLE_CONCEPT_HPP + +#include "isotropy.hpp" + +//point +#include "point_data.hpp" +#include "point_traits.hpp" +#include "point_concept.hpp" + +//interval +#include "interval_data.hpp" +#include "interval_traits.hpp" +#include "interval_concept.hpp" + +#include "rectangle_data.hpp" +#include "rectangle_traits.hpp" + +namespace boost { namespace polygon{ + struct rectangle_concept {}; + + template <typename T> + struct is_rectangle_concept { typedef gtl_no type; }; + template <> + struct is_rectangle_concept<rectangle_concept> { typedef gtl_yes type; }; + + template <typename T> + struct is_mutable_rectangle_concept { typedef gtl_no type; }; + template <> + struct is_mutable_rectangle_concept<rectangle_concept> { typedef gtl_yes type; }; + + template <> + struct geometry_domain<rectangle_concept> { typedef manhattan_domain type; }; + + template <typename T, typename CT> + struct rectangle_interval_type_by_concept { typedef void type; }; + template <typename T> + struct rectangle_interval_type_by_concept<T, gtl_yes> { typedef typename rectangle_traits<T>::interval_type type; }; + + template <typename T> + struct rectangle_interval_type { + typedef typename rectangle_interval_type_by_concept<T, typename is_rectangle_concept<typename geometry_concept<T>::type>::type>::type type; + }; + + template <typename T, typename CT> + struct rectangle_coordinate_type_by_concept { typedef void type; }; + template <typename T> + struct rectangle_coordinate_type_by_concept<T, gtl_yes> { typedef typename rectangle_traits<T>::coordinate_type type; }; + + template <typename T> + struct rectangle_coordinate_type { + typedef typename rectangle_coordinate_type_by_concept<T, typename is_rectangle_concept<typename geometry_concept<T>::type>::type>::type type; + }; + + template <typename T, typename CT> + struct rectangle_difference_type_by_concept { typedef void type; }; + template <typename T> + struct rectangle_difference_type_by_concept<T, gtl_yes> { + typedef typename coordinate_traits<typename rectangle_traits<T>::coordinate_type>::coordinate_difference type; }; + + template <typename T> + struct rectangle_difference_type { + typedef typename rectangle_difference_type_by_concept< + T, typename is_rectangle_concept<typename geometry_concept<T>::type>::type>::type type; + }; + + template <typename T, typename CT> + struct rectangle_distance_type_by_concept { typedef void type; }; + template <typename T> + struct rectangle_distance_type_by_concept<T, gtl_yes> { + typedef typename coordinate_traits<typename rectangle_traits<T>::coordinate_type>::coordinate_distance type; }; + + template <typename T> + struct rectangle_distance_type { + typedef typename rectangle_distance_type_by_concept< + T, typename is_rectangle_concept<typename geometry_concept<T>::type>::type>::type type; + }; + + template <typename T> + typename rectangle_interval_type<T>::type + get(const T& rectangle, orientation_2d orient, + typename enable_if< typename gtl_if<typename is_rectangle_concept<typename geometry_concept<T>::type>::type>::type>::type * = 0 + ) { + return rectangle_traits<T>::get(rectangle, orient); + } + + struct y_r_h : gtl_yes {}; + + template <typename T> + typename enable_if< typename gtl_and<y_r_h, typename gtl_if<typename is_rectangle_concept<typename geometry_concept<T>::type>::type>::type>::type, + typename rectangle_traits<T>::interval_type>::type + horizontal(const T& rectangle) { + return rectangle_traits<T>::get(rectangle, HORIZONTAL); + } + + struct y_r_v : gtl_yes {}; + + template <typename T> + typename enable_if< typename gtl_and<y_r_v, typename gtl_if<typename is_rectangle_concept<typename geometry_concept<T>::type>::type>::type>::type, + typename rectangle_traits<T>::interval_type>::type + vertical(const T& rectangle) { + return rectangle_traits<T>::get(rectangle, VERTICAL); + } + + struct y_r_set : gtl_yes {}; + + template <orientation_2d_enum orient, typename T, typename T2> + typename enable_if< typename gtl_and_3<y_r_set, typename is_mutable_rectangle_concept<typename geometry_concept<T>::type>::type, + typename is_interval_concept<typename geometry_concept<T2>::type>::type>::type, + void>::type + set(T& rectangle, const T2& interval) { + rectangle_mutable_traits<T>::set(rectangle, orient, interval); + } + + struct y_r_set2 : gtl_yes {}; + + template <typename T, typename T2> + typename enable_if< typename gtl_and_3<y_r_set2, typename is_mutable_rectangle_concept<typename geometry_concept<T>::type>::type, + typename is_interval_concept<typename geometry_concept<T2>::type>::type>::type, + void>::type + set(T& rectangle, orientation_2d orient, const T2& interval) { + rectangle_mutable_traits<T>::set(rectangle, orient, interval); + } + + struct y_r_h2 : gtl_yes {}; + + template <typename T, typename T2> + typename enable_if< typename gtl_and_3<y_r_h2, typename is_mutable_rectangle_concept<typename geometry_concept<T>::type>::type, + typename is_interval_concept<typename geometry_concept<T2>::type>::type>::type, + void>::type + horizontal(T& rectangle, const T2& interval) { + rectangle_mutable_traits<T>::set(rectangle, HORIZONTAL, interval); + } + + struct y_r_v2 : gtl_yes {}; + + template <typename T, typename T2> + typename enable_if< + typename gtl_and_3<y_r_v2, typename is_mutable_rectangle_concept<typename geometry_concept<T>::type>::type, + typename is_interval_concept<typename geometry_concept<T2>::type>::type>::type, void>::type + vertical(T& rectangle, const T2& interval) { + rectangle_mutable_traits<T>::set(rectangle, VERTICAL, interval); + } + + struct y_r_construct : gtl_yes {}; + + template <typename T, typename T2, typename T3> + typename enable_if< typename gtl_and<y_r_construct, typename is_mutable_rectangle_concept<typename geometry_concept<T>::type>::type>::type, + T>::type + construct(const T2& interval_horizontal, + const T3& interval_vertical) { + return rectangle_mutable_traits<T>::construct(interval_horizontal, interval_vertical); } + + struct y_r_construct2 : gtl_yes {}; + + template <typename T, typename coord_type> + typename enable_if< typename gtl_and<y_r_construct2, typename is_mutable_rectangle_concept<typename geometry_concept<T>::type>::type>::type, + T>::type + construct(coord_type xl, coord_type yl, coord_type xh, coord_type yh) { + return rectangle_mutable_traits<T>::construct(interval_data<coord_type>(xl, xh), + interval_data<coord_type>(yl, yh)); + } + + struct y_r_cconstruct : gtl_yes {}; + + template <typename T, typename T2> + typename enable_if< + typename gtl_and_3<y_r_cconstruct, + typename is_mutable_rectangle_concept<typename geometry_concept<T>::type>::type, + typename is_rectangle_concept<typename geometry_concept<T2>::type>::type>::type, + T>::type + copy_construct(const T2& rectangle) { + return construct<T> (get(rectangle, HORIZONTAL), get(rectangle, VERTICAL)); + } + + struct y_r_assign : gtl_yes {}; + + template <typename rectangle_type_1, typename rectangle_type_2> + typename enable_if< + typename gtl_and_3< y_r_assign, + typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + rectangle_type_1>::type & + assign(rectangle_type_1& lvalue, const rectangle_type_2& rvalue) { + set(lvalue, HORIZONTAL, get(rvalue, HORIZONTAL)); + set(lvalue, VERTICAL, get(rvalue, VERTICAL)); + return lvalue; + } + + struct y_r_equiv : gtl_yes {}; + + template <typename T, typename T2> + typename enable_if< + typename gtl_and_3< y_r_equiv, + typename is_rectangle_concept<typename geometry_concept<T>::type>::type, + typename is_rectangle_concept<typename geometry_concept<T2>::type>::type>::type, + bool>::type + equivalence(const T& rect1, const T2& rect2) { + return equivalence(get(rect1, HORIZONTAL), get(rect2, HORIZONTAL)) && + equivalence(get(rect1, VERTICAL), get(rect2, VERTICAL)); + } + + struct y_r_get : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if< typename gtl_and<y_r_get, typename gtl_if< typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type>::type, + typename rectangle_coordinate_type<rectangle_type>::type>::type + get(const rectangle_type& rectangle, orientation_2d orient, direction_1d dir) { + return get(rectangle_traits<rectangle_type>::get(rectangle, orient), dir); + } + + struct y_r_set3 : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_set3, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, void>::type + set(rectangle_type& rectangle, orientation_2d orient, direction_1d dir, + typename rectangle_traits<rectangle_type>::coordinate_type value) { + typename rectangle_traits<rectangle_type>::interval_type ivl = get(rectangle, orient); + set(ivl, dir, value); + set(rectangle, orient, ivl); + } + + struct y_r_xl : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if< typename gtl_and<y_r_xl, typename gtl_if< typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type>::type, + typename rectangle_coordinate_type<rectangle_type>::type>::type + xl(const rectangle_type& rectangle) { + return get(rectangle, HORIZONTAL, LOW); + } + + struct y_r_xl2 : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_xl2, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, void>::type + xl(rectangle_type& rectangle, typename rectangle_traits<rectangle_type>::coordinate_type value) { + return set(rectangle, HORIZONTAL, LOW, value); + } + + struct y_r_xh : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if< typename gtl_and<y_r_xh, typename gtl_if< typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type>::type, + typename rectangle_coordinate_type<rectangle_type>::type>::type + xh(const rectangle_type& rectangle) { + return get(rectangle, HORIZONTAL, HIGH); + } + + struct y_r_xh2 : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_xh2, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, void>::type + xh(rectangle_type& rectangle, typename rectangle_traits<rectangle_type>::coordinate_type value) { + return set(rectangle, HORIZONTAL, HIGH, value); + } + + struct y_r_yl : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if< typename gtl_and<y_r_yl, typename gtl_if< typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type>::type, + typename rectangle_coordinate_type<rectangle_type>::type>::type + yl(const rectangle_type& rectangle) { + return get(rectangle, VERTICAL, LOW); + } + + struct y_r_yl2 : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_yl2, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, void>::type + yl(rectangle_type& rectangle, typename rectangle_traits<rectangle_type>::coordinate_type value) { + return set(rectangle, VERTICAL, LOW, value); + } + + struct y_r_yh : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if< typename gtl_and<y_r_yh, typename gtl_if< typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type>::type, + typename rectangle_coordinate_type<rectangle_type>::type>::type + yh(const rectangle_type& rectangle) { + return get(rectangle, VERTICAL, HIGH); + } + + struct y_r_yh2 : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_yh2, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, void>::type + yh(rectangle_type& rectangle, typename rectangle_traits<rectangle_type>::coordinate_type value) { + return set(rectangle, VERTICAL, HIGH, value); + } + + struct y_r_ll : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_ll, typename gtl_if< typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type>::type, + point_data<typename rectangle_traits<rectangle_type>::coordinate_type> >::type + ll(const rectangle_type& rectangle) { + return point_data<typename rectangle_traits<rectangle_type>::coordinate_type> (xl(rectangle), yl(rectangle)); + } + + struct y_r_lr : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_lr, typename gtl_if< typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type>::type, + point_data<typename rectangle_traits<rectangle_type>::coordinate_type> >::type + lr(const rectangle_type& rectangle) { + return point_data<typename rectangle_traits<rectangle_type>::coordinate_type> (xh(rectangle), yl(rectangle)); + } + + struct y_r_ul : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_ul, typename gtl_if< typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type>::type, + point_data<typename rectangle_traits<rectangle_type>::coordinate_type> >::type + ul(const rectangle_type& rectangle) { + return point_data<typename rectangle_traits<rectangle_type>::coordinate_type> (xl(rectangle), yh(rectangle)); + } + + struct y_r_ur : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_ur, typename gtl_if< typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type>::type, + point_data<typename rectangle_traits<rectangle_type>::coordinate_type> >::type + ur(const rectangle_type& rectangle) { + return point_data<typename rectangle_traits<rectangle_type>::coordinate_type> (xh(rectangle), yh(rectangle)); + } + + struct y_r_contains : gtl_yes {}; + + template <typename rectangle_type, typename rectangle_type_2> + typename enable_if< typename gtl_and_3<y_r_contains, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + bool>::type + contains(const rectangle_type& rectangle, const rectangle_type_2 rectangle_contained, + bool consider_touch = true) { + return contains(horizontal(rectangle), horizontal(rectangle_contained), consider_touch) && + contains(vertical(rectangle), vertical(rectangle_contained), consider_touch); + } + + struct y_r_contains2 : gtl_yes {}; + + template <typename rectangle_type, typename point_type> + typename enable_if< typename gtl_and_3<y_r_contains2, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, + typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, bool>::type + contains(const rectangle_type& rectangle, const point_type point_contained, + bool consider_touch = true) { + return contains(horizontal(rectangle), x(point_contained), consider_touch) && + contains(vertical(rectangle), y(point_contained), consider_touch); + } + + struct y_r_set_points : gtl_yes {}; + + // set all four coordinates based upon two points + template <typename rectangle_type, typename point_type_1, typename point_type_2> + typename enable_if< typename gtl_and_4< y_r_set_points, + typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, + typename is_point_concept<typename geometry_concept<point_type_1>::type>::type, + typename is_point_concept<typename geometry_concept<point_type_2>::type>::type>::type, + rectangle_type>::type & + set_points(rectangle_type& rectangle, const point_type_1& p1, + const point_type_2& p2) { + typedef typename rectangle_traits<rectangle_type>::coordinate_type Unit; + Unit x1(x(p1)); + Unit x2(x(p2)); + Unit y1(y(p1)); + Unit y2(y(p2)); + horizontal(rectangle, construct<typename rectangle_traits<rectangle_type>::interval_type>(x1, x2)); + vertical(rectangle, construct<typename rectangle_traits<rectangle_type>::interval_type>(y1, y2)); + return rectangle; + } + + // move rectangle by delta in orient + template <typename rectangle_type> + rectangle_type& + move(rectangle_type& rectangle, orientation_2d orient, + typename coordinate_traits<typename rectangle_traits<rectangle_type>::coordinate_type>::coordinate_difference delta, + typename enable_if<typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type * = 0 + ) { + typename rectangle_traits<rectangle_type>::interval_type ivl = get(rectangle, orient); + move(ivl, delta); + set(rectangle, orient, ivl); + return rectangle; + } + + struct y_r_convolve : gtl_yes {}; + + // convolve this with b + template <typename rectangle_type_1, typename rectangle_type_2> + typename enable_if< + typename gtl_and_3< y_r_convolve, + typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + rectangle_type_1>::type & + convolve(rectangle_type_1& rectangle, + const rectangle_type_2& convolution_rectangle) { + typename rectangle_traits<rectangle_type_1>::interval_type ivl = horizontal(rectangle); + horizontal(rectangle, convolve(ivl, horizontal(convolution_rectangle))); + ivl = vertical(rectangle); + vertical(rectangle, convolve(ivl, vertical(convolution_rectangle))); + return rectangle; + } + + struct y_r_deconvolve : gtl_yes {}; + + // deconvolve this with b + template <typename rectangle_type_1, typename rectangle_type_2> + typename enable_if< typename gtl_and_3< y_r_deconvolve, + typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + rectangle_type_1>::type & + deconvolve(rectangle_type_1& rectangle, const rectangle_type_2& convolution_rectangle) { + typename rectangle_traits<rectangle_type_1>::interval_type ivl = horizontal(rectangle); + horizontal(rectangle, deconvolve(ivl, horizontal(convolution_rectangle))); + ivl = vertical(rectangle); + vertical(rectangle, deconvolve(ivl, vertical(convolution_rectangle))); + return rectangle; + } + + struct y_r_reconvolve : gtl_yes {}; + + // reflectedConvolve this with b + template <typename rectangle_type_1, typename rectangle_type_2> + typename enable_if< + typename gtl_and_3<y_r_reconvolve, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + rectangle_type_1>::type & + reflected_convolve(rectangle_type_1& rectangle, const rectangle_type_2& convolution_rectangle) { + typename rectangle_traits<rectangle_type_1>::interval_type ivl = horizontal(rectangle); + horizontal(rectangle, reflected_convolve(ivl, horizontal(convolution_rectangle))); + ivl = vertical(rectangle); + vertical(rectangle, reflected_convolve(ivl, vertical(convolution_rectangle))); + return rectangle; + } + + struct y_r_redeconvolve : gtl_yes {}; + + // reflectedDeconvolve this with b + // deconvolve this with b + template <typename rectangle_type_1, typename rectangle_type_2> + typename enable_if< + typename gtl_and_3<y_r_redeconvolve, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + rectangle_type_1>::type & + reflected_deconvolve(rectangle_type_1& rectangle, const rectangle_type_2& convolution_rectangle) { + typename rectangle_traits<rectangle_type_1>::interval_type ivl = horizontal(rectangle); + horizontal(rectangle, reflected_deconvolve(ivl, horizontal(convolution_rectangle))); + ivl = vertical(rectangle); + vertical(rectangle, reflected_deconvolve(ivl, vertical(convolution_rectangle))); + return rectangle; + } + + struct y_r_convolve2 : gtl_yes {}; + + // convolve with point + template <typename rectangle_type, typename point_type> + typename enable_if< typename gtl_and_3<y_r_convolve2, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, + typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, + rectangle_type>::type & + convolve(rectangle_type& rectangle, const point_type& convolution_point) { + typename rectangle_traits<rectangle_type>::interval_type ivl = horizontal(rectangle); + horizontal(rectangle, convolve(ivl, x(convolution_point))); + ivl = vertical(rectangle); + vertical(rectangle, convolve(ivl, y(convolution_point))); + return rectangle; + } + + struct y_r_deconvolve2 : gtl_yes {}; + + // deconvolve with point + template <typename rectangle_type, typename point_type> + typename enable_if< + typename gtl_and_3<y_r_deconvolve2, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, + typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, rectangle_type>::type & + deconvolve(rectangle_type& rectangle, const point_type& convolution_point) { + typename rectangle_traits<rectangle_type>::interval_type ivl = horizontal(rectangle); + horizontal(rectangle, deconvolve(ivl, x(convolution_point))); + ivl = vertical(rectangle); + vertical(rectangle, deconvolve(ivl, y(convolution_point))); + return rectangle; + } + + struct y_r_delta : gtl_yes {}; + + // get the magnitude of the interval range depending on orient + template <typename rectangle_type> + typename enable_if< typename gtl_and<y_r_delta, typename gtl_if<typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type>::type, + typename rectangle_difference_type<rectangle_type>::type>::type + delta(const rectangle_type& rectangle, orientation_2d orient) { + return delta(get(rectangle, orient)); + } + + struct y_r_area : gtl_yes {}; + + // get the area of the rectangle + template <typename rectangle_type> + typename enable_if< typename gtl_and<y_r_area, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + typename coordinate_traits<typename rectangle_traits<rectangle_type>::coordinate_type>::manhattan_area_type>::type + area(const rectangle_type& rectangle) { + typedef typename coordinate_traits<typename rectangle_traits<rectangle_type>::coordinate_type>::manhattan_area_type area_type; + return (area_type)delta(rectangle, HORIZONTAL) * (area_type)delta(rectangle, VERTICAL); + } + + struct y_r_go : gtl_yes {}; + + // returns the orientation of the longest side + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_go, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + orientation_2d>::type + guess_orientation(const rectangle_type& rectangle) { + return delta(rectangle, HORIZONTAL) >= delta(rectangle, VERTICAL) ? + HORIZONTAL : VERTICAL; + } + + struct y_r_half_p : gtl_yes {}; + + // get the half perimeter of the rectangle + template <typename rectangle_type> + typename enable_if< typename gtl_and<y_r_half_p, typename gtl_if<typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type>::type, + typename rectangle_difference_type<rectangle_type>::type>::type + half_perimeter(const rectangle_type& rectangle) { + return delta(rectangle, HORIZONTAL) + delta(rectangle, VERTICAL); + } + + // get the perimeter of the rectangle + template <typename rectangle_type> + typename rectangle_difference_type<rectangle_type>::type + perimeter(const rectangle_type& rectangle, + typename enable_if< typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type * = 0 + ) { + return 2 * half_perimeter(rectangle); + } + + struct y_r_intersects : gtl_yes {}; + + // check if Rectangle b intersects `this` Rectangle + // [in] b Rectangle that will be checked + // [in] considerTouch If true, return true even if b touches the boundary + // [ret] . true if `t` intersects b + template <typename rectangle_type_1, typename rectangle_type_2> + typename enable_if< + typename gtl_and_3<y_r_intersects, typename is_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + bool>::type + intersects(const rectangle_type_1& rectangle, const rectangle_type_2& b, bool consider_touch = true) { + return intersects(horizontal(rectangle), horizontal(b), consider_touch) && + intersects(vertical(rectangle), vertical(b), consider_touch); + } + + struct y_r_b_intersect : gtl_yes {}; + + // Check if boundaries of Rectangle b and `this` Rectangle intersect + // [in] b Rectangle that will be checked + // [in] considerTouch If true, return true even if p is on the foundary + // [ret] . true if `t` contains p + template <typename rectangle_type_1, typename rectangle_type_2> + typename enable_if< + typename gtl_and_3<y_r_b_intersect, typename is_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + bool>::type + boundaries_intersect(const rectangle_type_1& rectangle, const rectangle_type_2& b, + bool consider_touch = true) { + return (intersects(rectangle, b, consider_touch) && + !(contains(rectangle, b, !consider_touch)) && + !(contains(b, rectangle, !consider_touch))); + } + + struct y_r_b_abuts : gtl_yes {}; + + // check if b is touching 'this' on the end specified by dir + template <typename rectangle_type_1, typename rectangle_type_2> + typename enable_if< typename gtl_and_3<y_r_b_abuts, typename is_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + bool>::type + abuts(const rectangle_type_1& rectangle, const rectangle_type_2& b, + direction_2d dir) { + return + abuts(get(rectangle, orientation_2d(dir)), + get(b, orientation_2d(dir)), + direction_1d(dir)) && + intersects(get(rectangle, orientation_2d(dir).get_perpendicular()), + get(b, orientation_2d(dir).get_perpendicular()), true); + } + + struct y_r_b_abuts2 : gtl_yes {}; + + // check if they are touching in the given orientation + template <typename rectangle_type_1, typename rectangle_type_2> + typename enable_if< typename gtl_and_3<y_r_b_abuts2, typename is_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + bool>::type + abuts(const rectangle_type_1& rectangle, const rectangle_type_2& b, + orientation_2d orient) { + return + abuts(get(rectangle, orient), get(b, orient)) && + intersects(get(rectangle, orient.get_perpendicular()), + get(b, orient.get_perpendicular()), true); + } + + struct y_r_b_abuts3 : gtl_yes {}; + + // check if they are touching but not overlapping + template <typename rectangle_type_1, typename rectangle_type_2> + typename enable_if< typename gtl_and_3<y_r_b_abuts3, typename is_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + bool>::type + abuts(const rectangle_type_1& rectangle, const rectangle_type_2& b) { + return abuts(rectangle, b, HORIZONTAL) || abuts(rectangle, b, VERTICAL); + } + + struct y_r_b_intersect2 : gtl_yes {}; + + // intersect rectangle with interval on orient + template <typename rectangle_type, typename interval_type> + typename enable_if< + typename gtl_and_3<y_r_b_intersect2, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, + bool>::type + intersect(rectangle_type& rectangle, const interval_type& b, + orientation_2d orient, bool consider_touch = true) { + typename rectangle_traits<rectangle_type>::interval_type ivl = get(rectangle, orient); + if(intersect(ivl, b, consider_touch)) { + set(rectangle, orient, ivl); + return true; + } + return false; + } + + struct y_r_b_intersect3 : gtl_yes {}; + + // clip rectangle to b + template <typename rectangle_type_1, typename rectangle_type_2> + typename enable_if< typename gtl_and_3<y_r_b_intersect3, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + bool>::type + intersect(rectangle_type_1& rectangle, const rectangle_type_2& b, bool consider_touch = true) { + if(intersects(rectangle, b)) { + intersect(rectangle, horizontal(b), HORIZONTAL, consider_touch); + intersect(rectangle, vertical(b), VERTICAL, consider_touch); + return true; + } + return false; + } + + struct y_r_g_intersect : gtl_yes {}; + + // Sets this to the generalized intersection of this and the given rectangle + template <typename rectangle_type_1, typename rectangle_type_2> + typename enable_if< typename gtl_and_3<y_r_g_intersect, + typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + rectangle_type_1>::type & + generalized_intersect(rectangle_type_1& rectangle, const rectangle_type_2& b) { + typename rectangle_traits<rectangle_type_1>::interval_type ivl = get(rectangle, HORIZONTAL); + generalized_intersect(ivl, horizontal(b)); + horizontal(rectangle, ivl); + ivl = vertical(rectangle); + generalized_intersect(ivl, vertical(b)); + vertical(rectangle, ivl); + return rectangle; + } + + struct y_r_bloat : gtl_yes {}; + + // bloat the interval specified by orient by bloating + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_bloat, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + rectangle_type>::type & + bloat(rectangle_type& rectangle, orientation_2d orient, + typename rectangle_traits<rectangle_type>::coordinate_type bloating) { + typename rectangle_traits<rectangle_type>::interval_type ivl = get(rectangle, orient); + bloat(ivl, bloating); + set(rectangle, orient, ivl); + return rectangle; + } + + struct y_r_bloat2 : gtl_yes {}; + + // bloat the Rectangle by bloating + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_bloat2, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + rectangle_type>::type & + bloat(rectangle_type& rectangle, + typename rectangle_traits<rectangle_type>::coordinate_type bloating) { + bloat(rectangle, HORIZONTAL, bloating); + return bloat(rectangle, VERTICAL, bloating); + } + + struct y_r_bloat3 : gtl_yes {}; + + // bloat the interval cooresponding to orient by bloating in dir direction + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_bloat3, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + rectangle_type>::type & + bloat(rectangle_type& rectangle, direction_2d dir, + typename rectangle_traits<rectangle_type>::coordinate_type bloating) { + typename rectangle_traits<rectangle_type>::interval_type ivl = get(rectangle, orientation_2d(dir)); + bloat(ivl, direction_1d(dir), bloating); + set(rectangle, orientation_2d(dir), ivl); + return rectangle; + } + + struct y_r_shrink : gtl_yes {}; + + // shrink the interval specified by orient by bloating + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_shrink, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + rectangle_type>::type & + shrink(rectangle_type& rectangle, orientation_2d orient, + typename rectangle_traits<rectangle_type>::coordinate_type shrinking) { + return bloat(rectangle, orient, -shrinking); + } + + struct y_r_shrink2 : gtl_yes {}; + + // shrink the Rectangle by bloating + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_shrink2, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + rectangle_type>::type & + shrink(rectangle_type& rectangle, + typename rectangle_traits<rectangle_type>::coordinate_type shrinking) { + return bloat(rectangle, -shrinking); + } + + struct y_r_shrink3 : gtl_yes {}; + + // shrink the interval cooresponding to orient by bloating in dir direction + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_shrink3, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + rectangle_type>::type & + shrink(rectangle_type& rectangle, direction_2d dir, + typename rectangle_traits<rectangle_type>::coordinate_type shrinking) { + return bloat(rectangle, dir, -shrinking); + } + + struct y_r_encompass : gtl_yes {}; + + // encompass interval on orient + template <typename rectangle_type, typename interval_type> + typename enable_if< + typename gtl_and_3<y_r_encompass, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, + typename is_interval_concept<typename geometry_concept<interval_type>::type>::type>::type, + bool>::type + encompass(rectangle_type& rectangle, const interval_type& b, + orientation_2d orient) { + typename rectangle_traits<rectangle_type>::interval_type ivl = get(rectangle, orient); + if(encompass(ivl, b)) { + set(rectangle, orient, ivl); + return true; + } + return false; + } + + struct y_r_encompass2 : gtl_yes {}; + + // enlarge rectangle to encompass the Rectangle b + template <typename rectangle_type_1, typename rectangle_type_2> + bool + encompass(rectangle_type_1& rectangle, const rectangle_type_2& b, + typename enable_if< typename gtl_and_3<y_r_encompass2, + typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type >::type>::type * = 0 + ) { + //note that operator | is intentional because both should be called regardless + return encompass(rectangle, horizontal(b), HORIZONTAL) | + encompass(rectangle, vertical(b), VERTICAL); + } + + struct y_r_encompass3 : gtl_yes {}; + + // enlarge rectangle to encompass the point b + template <typename rectangle_type_1, typename point_type> + typename enable_if< + typename gtl_and_3<y_r_encompass3, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, + bool>::type + encompass(rectangle_type_1& rectangle, const point_type& b, + typename enable_if< + typename gtl_and< typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type>::type * = 0 + ) { + typename rectangle_traits<rectangle_type_1>::interval_type hivl, vivl; + hivl = horizontal(rectangle); + vivl = vertical(rectangle); + //note that operator | is intentional because both should be called regardless + bool retval = encompass(hivl, x(b)) | encompass(vivl, y(b)); + if(retval) { + horizontal(rectangle, hivl); + vertical(rectangle, vivl); + } + return retval; + } + + struct y_r_center : gtl_yes {}; + + // returns the center of the rectangle + template <typename point_type, typename rectangle_type> + typename enable_if< + typename gtl_and_3<y_r_center, typename is_mutable_point_concept<typename geometry_concept<point_type>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + bool>::type + center(point_type& center_point, const rectangle_type& rectangle) { + center_point = construct<point_type>(center(horizontal(rectangle)), + center(vertical(rectangle))); + return true; + } + + struct y_r_get_corner : gtl_yes {}; + + template <typename point_type, typename rectangle_type> + typename enable_if< + typename gtl_and_3<y_r_get_corner, typename is_mutable_point_concept<typename geometry_concept<point_type>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + bool>::type + get_corner(point_type& corner_point, const rectangle_type& rectangle, direction_2d direction_facing, direction_1d direction_turning) { + typedef typename rectangle_traits<rectangle_type>::coordinate_type Unit; + Unit u1 = get(rectangle, direction_facing); + Unit u2 = get(rectangle, direction_facing.turn(direction_turning)); + if(orientation_2d(direction_facing).to_int()) std::swap(u1, u2); + corner_point = construct<point_type>(u1, u2); + return true; + } + + struct y_r_get_half : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_get_half, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + rectangle_type>::type + get_half(const rectangle_type& rectangle, direction_2d dir) { + rectangle_type retval(rectangle); + set(retval, orientation_2d(dir), get_half(get(rectangle, orientation_2d(dir)), direction_1d(dir))); + return retval; + } + + struct y_r_join_with : gtl_yes {}; + + template <typename rectangle_type_1, typename rectangle_type_2> + typename enable_if< typename gtl_and_3<y_r_join_with, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + bool>::type + join_with(rectangle_type_1& rectangle, const rectangle_type_2& b) { + typedef typename rectangle_traits<rectangle_type_1>::interval_type Interval1; + typedef typename rectangle_traits<rectangle_type_2>::interval_type Interval2; + Interval1 hi1 = get(rectangle, HORIZONTAL); + Interval1 vi1 = get(rectangle, VERTICAL); + Interval2 hi2 = get(b, HORIZONTAL), vi2 = get(b, VERTICAL); + Interval1 temp; + if (equivalence(hi1, hi2) && join_with(vi1, vi2)) { + vertical(rectangle, vi1); + return true; + } + if (equivalence(vi1, vi2) && join_with(hi1, hi2)) { + horizontal(rectangle, hi1); + return true; + } + return false; + } + + struct y_r_eda2 : gtl_yes {}; + + template <typename rectangle_type, typename point_type> + typename enable_if< typename gtl_and_3<y_r_eda2, + typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, + typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, + typename rectangle_difference_type<rectangle_type>::type>::type + euclidean_distance(const rectangle_type& lvalue, const point_type& rvalue, orientation_2d orient) { + return euclidean_distance(get(lvalue, orient), get(rvalue, orient)); + } + + struct y_r_eda : gtl_yes {}; + + template <typename rectangle_type, typename rectangle_type_2> + typename enable_if< + typename gtl_and_3<y_r_eda, + typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + typename rectangle_difference_type<rectangle_type>::type>::type + euclidean_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue, orientation_2d orient) { + return euclidean_distance(get(lvalue, orient), get(rvalue, orient)); + } + + struct y_r_sed : gtl_yes {}; + + template <typename rectangle_type, typename point_type> + typename enable_if< typename gtl_if< typename gtl_and_3<y_r_sed, + typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, + typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type>::type, + typename rectangle_difference_type<rectangle_type>::type>::type + square_euclidean_distance(rectangle_type& lvalue, const point_type& rvalue) { + typename coordinate_traits<typename rectangle_traits<rectangle_type>::coordinate_type>::coordinate_difference xdist, ydist; + xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); + ydist = euclidean_distance(lvalue, rvalue, VERTICAL); + return (xdist * xdist) + (ydist * ydist); + } + + struct y_r_sed2 : gtl_yes {}; + + template <typename rectangle_type, typename rectangle_type_2> + typename enable_if< + typename gtl_and_3<y_r_sed2, typename is_rectangle_concept< typename geometry_concept<rectangle_type>::type>::type, + typename is_rectangle_concept< typename geometry_concept<rectangle_type_2>::type>::type>::type, + typename rectangle_difference_type<rectangle_type>::type>::type + square_euclidean_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue) { + typename coordinate_traits<typename rectangle_traits<rectangle_type>::coordinate_type>::coordinate_difference xdist, ydist; + xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); + ydist = euclidean_distance(lvalue, rvalue, VERTICAL); + return (xdist * xdist) + (ydist * ydist); + } + + struct y_r_edist : gtl_yes {}; + + template <typename rectangle_type, typename point_type> + typename enable_if< typename gtl_and_3<y_r_edist, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, + typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, + typename rectangle_distance_type<rectangle_type>::type>::type + euclidean_distance(rectangle_type& lvalue, const point_type& rvalue) { + return sqrt((double) + (square_euclidean_distance(lvalue, rvalue))); + } + + struct y_r_edist2 : gtl_yes {}; + + template <typename rectangle_type, typename rectangle_type_2> + typename enable_if< typename gtl_and_3<y_r_edist2, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + typename rectangle_distance_type<rectangle_type>::type>::type + euclidean_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue) { + double val = (int)square_euclidean_distance(lvalue, rvalue); + return sqrt(val); + } + + struct y_r_mdist : gtl_yes {}; + + template <typename rectangle_type, typename point_type> + typename enable_if< + typename gtl_and_3<y_r_mdist, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, + typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type, + typename rectangle_difference_type<rectangle_type>::type>::type + manhattan_distance(rectangle_type& lvalue, const point_type& rvalue) { + typename coordinate_traits<typename rectangle_traits<rectangle_type>::coordinate_type>::coordinate_difference xdist, ydist; + xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); + ydist = euclidean_distance(lvalue, rvalue, VERTICAL); + return xdist + ydist; + } + + struct y_r_mdist2 : gtl_yes {}; + + template <typename rectangle_type, typename rectangle_type_2> + typename enable_if< + typename gtl_and_3<y_r_mdist2, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + typename rectangle_difference_type<rectangle_type>::type>::type + manhattan_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue) { + typename coordinate_traits<typename rectangle_traits<rectangle_type>::coordinate_type>::coordinate_difference xdist, ydist; + xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); + ydist = euclidean_distance(lvalue, rvalue, VERTICAL); + return xdist + ydist; + } + + struct y_r_scale_up : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_scale_up, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + rectangle_type>::type & + scale_up(rectangle_type& rectangle, + typename coordinate_traits<typename rectangle_traits<rectangle_type>::coordinate_type>::unsigned_area_type factor) { + horizontal(rectangle, scale_up(horizontal(rectangle), factor)); + vertical(rectangle, scale_up(vertical(rectangle), factor)); + return rectangle; + } + + struct y_r_scale_down : gtl_yes {}; + + template <typename rectangle_type> + typename enable_if<typename gtl_and<y_r_scale_down, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + rectangle_type>::type & + scale_down(rectangle_type& rectangle, + typename coordinate_traits<typename rectangle_traits<rectangle_type>::coordinate_type>::unsigned_area_type factor) { + horizontal(rectangle, scale_down(horizontal(rectangle), factor)); + vertical(rectangle, scale_down(vertical(rectangle), factor)); + return rectangle; + } + + struct y_r_scale : gtl_yes {}; + + template <typename rectangle_type, typename scaling_type> + typename enable_if<typename gtl_and<y_r_scale, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + rectangle_type>::type & + scale(rectangle_type& rectangle, const scaling_type& scaling) { + point_data<typename rectangle_traits<rectangle_type>::coordinate_type> llp(xl(rectangle), yl(rectangle)); + point_data<typename rectangle_traits<rectangle_type>::coordinate_type> urp(xl(rectangle), yl(rectangle)); + scale(llp, scaling); + scale(urp, scaling); + set_points(rectangle, llp, urp); + return rectangle; + } + + struct y_r_transform : gtl_yes {}; + + template <typename rectangle_type, typename transformation_type> + typename enable_if<typename gtl_and<y_r_transform, typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type>::type, + rectangle_type>::type & + transform(rectangle_type& rectangle, const transformation_type& transformation) { + point_data<typename rectangle_traits<rectangle_type>::coordinate_type> llp(xl(rectangle), yl(rectangle)); + point_data<typename rectangle_traits<rectangle_type>::coordinate_type> urp(xh(rectangle), yh(rectangle)); + transform(llp, transformation); + transform(urp, transformation); + set_points(rectangle, llp, urp); + return rectangle; + } + + template <typename rectangle_type_1, typename rectangle_type_2> + class less_rectangle_concept { + private: + orientation_2d orient_; + public: + inline less_rectangle_concept(orientation_2d orient = VERTICAL) : orient_(orient) {} + typename enable_if< + typename gtl_and< typename is_rectangle_concept<typename geometry_concept<rectangle_type_1>::type>::type, + typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type, + bool>::type + operator () (const rectangle_type_1& a, + const rectangle_type_2& b) const { + typedef typename rectangle_traits<rectangle_type_1>::coordinate_type Unit; + Unit vl1 = get(get(a, orient_), LOW); + Unit vl2 = get(get(b, orient_), LOW); + if(vl1 > vl2) return false; + if(vl1 == vl2) { + orientation_2d perp = orient_.get_perpendicular(); + Unit hl1 = get(get(a, perp), LOW); + Unit hl2 = get(get(b, perp), LOW); + if(hl1 > hl2) return false; + if(hl1 == hl2) { + Unit vh1 = get(get(a, orient_), HIGH); + Unit vh2 = get(get(b, orient_), HIGH); + if(vh1 > vh2) return false; + if(vh1 == vh2) { + Unit hh1 = get(get(a, perp), HIGH); + Unit hh2 = get(get(b, perp), HIGH); + return hh1 < hh2; + } + } + } + return true; + } + + }; + + template <typename T> + template <typename interval_type_1> + inline void rectangle_data<T>::set(orientation_2d orient, const interval_type_1& interval) { + assign(ranges_[orient.to_int()], interval); + } + + template <class T> + template <class T2> + rectangle_data<T>& rectangle_data<T>::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template <class T> + template <class T2> + bool rectangle_data<T>::operator==(const T2& rvalue) const { + return equivalence(*this, rvalue); + } + + template <typename T> + struct geometry_concept<rectangle_data<T> > { + typedef rectangle_concept type; + }; +} +} +#endif + diff --git a/boost/polygon/rectangle_data.hpp b/boost/polygon/rectangle_data.hpp new file mode 100644 index 0000000000..2bcbb461d8 --- /dev/null +++ b/boost/polygon/rectangle_data.hpp @@ -0,0 +1,64 @@ +/* + 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_RECTANGLE_DATA_HPP +#define BOOST_POLYGON_RECTANGLE_DATA_HPP + +#include "isotropy.hpp" +//interval +#include "interval_data.hpp" + +namespace boost { namespace polygon{ + +template <typename T> +class rectangle_data { +public: + typedef T coordinate_type; + typedef interval_data<T> interval_type; + inline rectangle_data():ranges_() {} + inline rectangle_data(T xl, T yl, T xh, T yh):ranges_() { + if(xl > xh) std::swap(xl, xh); + if(yl > yh) std::swap(yl, yh); + ranges_[HORIZONTAL] = interval_data<T>(xl, xh); + ranges_[VERTICAL] = interval_data<T>(yl, yh); + } + template <typename interval_type_1, typename interval_type_2> + inline rectangle_data(const interval_type_1& hrange, + const interval_type_2& vrange):ranges_() { + set(HORIZONTAL, hrange); set(VERTICAL, vrange); } + + inline rectangle_data(const rectangle_data& that):ranges_() { (*this) = that; } + inline rectangle_data& operator=(const rectangle_data& that) { + ranges_[0] = that.ranges_[0]; ranges_[1] = that.ranges_[1]; return *this; + } + template <typename T2> + inline rectangle_data& operator=(const T2& rvalue); + + template <typename T2> + inline bool operator==(const T2& rvalue) const; + template <typename T2> + inline bool operator!=(const T2& rvalue) const { return !((*this) == rvalue); } + + inline interval_data<coordinate_type> get(orientation_2d orient) const { + return ranges_[orient.to_int()]; } + inline coordinate_type get(direction_2d dir) const { + return ranges_[orientation_2d(dir).to_int()].get(direction_1d(dir)); + } + inline void set(direction_2d dir, coordinate_type value) { + return ranges_[orientation_2d(dir).to_int()].set(direction_1d(dir), value); + } + template <typename interval_type_1> + inline void set(orientation_2d orient, const interval_type_1& interval); +private: + interval_data<coordinate_type> ranges_[2]; +}; + + +} +} +#endif + diff --git a/boost/polygon/rectangle_traits.hpp b/boost/polygon/rectangle_traits.hpp new file mode 100644 index 0000000000..fe777a4fe1 --- /dev/null +++ b/boost/polygon/rectangle_traits.hpp @@ -0,0 +1,38 @@ +/* + 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_RECTANGLE_TRAITS_HPP +#define BOOST_POLYGON_RECTANGLE_TRAITS_HPP +namespace boost { namespace polygon{ + + template <typename T, typename enable = gtl_yes> + struct rectangle_traits {}; + template <typename T> + struct rectangle_traits<T, gtl_no> {}; + + template <typename T> + struct rectangle_traits<T, typename gtl_same_type<typename T::interval_type, typename T::interval_type>::type> { + typedef typename T::coordinate_type coordinate_type; + typedef typename T::interval_type interval_type; + static inline interval_type get(const T& rectangle, orientation_2d orient) { + return rectangle.get(orient); } + }; + + template <typename T> + struct rectangle_mutable_traits { + template <typename T2> + static inline void set(T& rectangle, orientation_2d orient, const T2& interval) { + rectangle.set(orient, interval); } + template <typename T2, typename T3> + static inline T construct(const T2& interval_horizontal, + const T3& interval_vertical) { + return T(interval_horizontal, interval_vertical); } + }; +} +} +#endif + diff --git a/boost/polygon/transform.hpp b/boost/polygon/transform.hpp new file mode 100644 index 0000000000..16b566d36a --- /dev/null +++ b/boost/polygon/transform.hpp @@ -0,0 +1,501 @@ +/* + 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_TRANSFORM_HPP +#define BOOST_POLYGON_TRANSFORM_HPP +#include "isotropy.hpp" +#include "point_3d_concept.hpp" +namespace boost { namespace polygon{ +// Transformation of Coordinate Systems +// Enum meaning: +// Select which direction_3d to change the positive direction of each +// axis in the old coordinate system to map it to the new coordiante system. +// The first direction_3d listed for each enum is the direction to map the +// positive horizontal direction to. +// The second direction_3d listed for each enum is the direction to map the +// positive vertical direction to. +// The third direction_3d listed for each enum is the direction to map the +// positive proximal direction to. +// The zero position bit (LSB) indicates whether the horizontal axis flips +// when transformed. +// The 1st postion bit indicates whether the vertical axis flips when +// transformed. +// The 2nd position bit indicates whether the horizontal and vertical axis +// swap positions when transformed. +// Note that the first eight values are the complete set of 2D transforms. +// The 3rd position bit indicates whether the proximal axis flips when +// transformed. +// The 4th position bit indicates whether the proximal and horizontal axis are +// swapped when transformed. It changes the meaning of the 2nd position bit +// to mean that the horizontal and vertical axis are swapped in their new +// positions, naturally. +// The 5th position bit (MSB) indicates whether the proximal and vertical axis +// are swapped when transformed. It is mutually exclusive with the 4th postion +// bit, making the maximum legal value 48 (decimal). It similarly changes the +// meaning of the 2nd position bit to mean that the horizontal and vertical are +// swapped in their new positions. +// Enum Values: +// 000000 EAST NORTH UP +// 000001 WEST NORTH UP +// 000010 EAST SOUTH UP +// 000011 WEST SOUTH UP +// 000100 NORTH EAST UP +// 000101 SOUTH EAST UP +// 000110 NORTH WEST UP +// 000111 SOUTH WEST UP +// 001000 EAST NORTH DOWN +// 001001 WEST NORTH DOWN +// 001010 EAST SOUTH DOWN +// 001011 WEST SOUTH DOWN +// 001100 NORTH EAST DOWN +// 001101 SOUTH EAST DOWN +// 001110 NORTH WEST DOWN +// 001111 SOUTH WEST DOWN +// 010000 UP NORTH EAST +// 010001 DOWN NORTH EAST +// 010010 UP SOUTH EAST +// 010011 DOWN SOUTH EAST +// 010100 NORTH UP EAST +// 010101 SOUTH UP EAST +// 010110 NORTH DOWN EAST +// 010111 SOUTH DOWN EAST +// 011000 UP NORTH WEST +// 011001 DOWN NORTH WEST +// 011010 UP SOUTH WEST +// 011011 DOWN SOUTH WEST +// 011100 NORTH UP WEST +// 011101 SOUTH UP WEST +// 011110 NORTH DOWN WEST +// 011111 SOUTH DOWN WEST +// 100000 EAST UP NORTH +// 100001 WEST UP NORTH +// 100010 EAST DOWN NORTH +// 100011 WEST DOWN NORTH +// 100100 UP EAST NORTH +// 100101 DOWN EAST NORTH +// 100110 UP WEST NORTH +// 100111 DOWN WEST NORTH +// 101000 EAST UP SOUTH +// 101001 WEST UP SOUTH +// 101010 EAST DOWN SOUTH +// 101011 WEST DOWN SOUTH +// 101100 UP EAST SOUTH +// 101101 DOWN EAST SOUTH +// 101110 UP WEST SOUTH +// 101111 DOWN WEST SOUTH +class axis_transformation { +public: + // Enum Names and values + // NULL_TRANSFORM = 0, BEGIN_TRANSFORM = 0, + // ENU = 0, EAST_NORTH_UP = 0, EN = 0, EAST_NORTH = 0, + // WNU = 1, WEST_NORTH_UP = 1, WN = 1, WEST_NORTH = 1, FLIP_X = 1, + // ESU = 2, EAST_SOUTH_UP = 2, ES = 2, EAST_SOUTH = 2, FLIP_Y = 2, + // WSU = 3, WEST_SOUTH_UP = 3, WS = 3, WEST_SOUTH = 3, + // NEU = 4, NORTH_EAST_UP = 4, NE = 4, NORTH_EAST = 4, SWAP_XY = 4, + // SEU = 5, SOUTH_EAST_UP = 5, SE = 5, SOUTH_EAST = 5, + // NWU = 6, NORTH_WEST_UP = 6, NW = 6, NORTH_WEST = 6, + // SWU = 7, SOUTH_WEST_UP = 7, SW = 7, SOUTH_WEST = 7, + // END_2D_TRANSFORM = 7, + // END = 8, EAST_NORTH_DOWN = 8, + // WND = 9, WEST_NORTH_DOWN = 9, + // ESD = 10, EAST_SOUTH_DOWN = 10, + // WSD = 11, WEST_SOUTH_DOWN = 11, + // NED = 12, NORTH_EAST_DOWN = 12, + // SED = 13, SOUTH_EAST_DOWN = 13, + // NWD = 14, NORTH_WEST_DOWN = 14, + // SWD = 15, SOUTH_WEST_DOWN = 15, + // UNE = 16, UP_NORTH_EAST = 16, + // DNE = 17, DOWN_NORTH_EAST = 17, + // USE = 18, UP_SOUTH_EAST = 18, + // DSE = 19, DOWN_SOUTH_EAST = 19, + // NUE = 20, NORTH_UP_EAST = 20, + // SUE = 21, SOUTH_UP_EAST = 21, + // NDE = 22, NORTH_DOWN_EAST = 22, + // SDE = 23, SOUTH_DOWN_EAST = 23, + // UNW = 24, UP_NORTH_WEST = 24, + // DNW = 25, DOWN_NORTH_WEST = 25, + // USW = 26, UP_SOUTH_WEST = 26, + // DSW = 27, DOWN_SOUTH_WEST = 27, + // NUW = 28, NORTH_UP_WEST = 28, + // SUW = 29, SOUTH_UP_WEST = 29, + // NDW = 30, NORTH_DOWN_WEST = 30, + // SDW = 31, SOUTH_DOWN_WEST = 31, + // EUN = 32, EAST_UP_NORTH = 32, + // WUN = 33, WEST_UP_NORTH = 33, + // EDN = 34, EAST_DOWN_NORTH = 34, + // WDN = 35, WEST_DOWN_NORTH = 35, + // UEN = 36, UP_EAST_NORTH = 36, + // DEN = 37, DOWN_EAST_NORTH = 37, + // UWN = 38, UP_WEST_NORTH = 38, + // DWN = 39, DOWN_WEST_NORTH = 39, + // EUS = 40, EAST_UP_SOUTH = 40, + // WUS = 41, WEST_UP_SOUTH = 41, + // EDS = 42, EAST_DOWN_SOUTH = 42, + // WDS = 43, WEST_DOWN_SOUTH = 43, + // UES = 44, UP_EAST_SOUTH = 44, + // DES = 45, DOWN_EAST_SOUTH = 45, + // UWS = 46, UP_WEST_SOUTH = 46, + // DWS = 47, DOWN_WEST_SOUTH = 47, END_TRANSFORM = 47 + enum ATR { + NULL_TRANSFORM = 0, BEGIN_TRANSFORM = 0, + ENU = 0, EAST_NORTH_UP = 0, EN = 0, EAST_NORTH = 0, + WNU = 1, WEST_NORTH_UP = 1, WN = 1, WEST_NORTH = 1, FLIP_X = 1, + ESU = 2, EAST_SOUTH_UP = 2, ES = 2, EAST_SOUTH = 2, FLIP_Y = 2, + WSU = 3, WEST_SOUTH_UP = 3, WS = 3, WEST_SOUTH = 3, FLIP_XY = 3, + NEU = 4, NORTH_EAST_UP = 4, NE = 4, NORTH_EAST = 4, SWAP_XY = 4, + SEU = 5, SOUTH_EAST_UP = 5, SE = 5, SOUTH_EAST = 5, ROTATE_LEFT = 5, + NWU = 6, NORTH_WEST_UP = 6, NW = 6, NORTH_WEST = 6, ROTATE_RIGHT = 6, + SWU = 7, SOUTH_WEST_UP = 7, SW = 7, SOUTH_WEST = 7, FLIP_SWAP_XY = 7, END_2D_TRANSFORM = 7, + END = 8, EAST_NORTH_DOWN = 8, FLIP_Z = 8, + WND = 9, WEST_NORTH_DOWN = 9, + ESD = 10, EAST_SOUTH_DOWN = 10, + WSD = 11, WEST_SOUTH_DOWN = 11, + NED = 12, NORTH_EAST_DOWN = 12, + SED = 13, SOUTH_EAST_DOWN = 13, + NWD = 14, NORTH_WEST_DOWN = 14, + SWD = 15, SOUTH_WEST_DOWN = 15, + UNE = 16, UP_NORTH_EAST = 16, + DNE = 17, DOWN_NORTH_EAST = 17, + USE = 18, UP_SOUTH_EAST = 18, + DSE = 19, DOWN_SOUTH_EAST = 19, + NUE = 20, NORTH_UP_EAST = 20, + SUE = 21, SOUTH_UP_EAST = 21, + NDE = 22, NORTH_DOWN_EAST = 22, + SDE = 23, SOUTH_DOWN_EAST = 23, + UNW = 24, UP_NORTH_WEST = 24, + DNW = 25, DOWN_NORTH_WEST = 25, + USW = 26, UP_SOUTH_WEST = 26, + DSW = 27, DOWN_SOUTH_WEST = 27, + NUW = 28, NORTH_UP_WEST = 28, + SUW = 29, SOUTH_UP_WEST = 29, + NDW = 30, NORTH_DOWN_WEST = 30, + SDW = 31, SOUTH_DOWN_WEST = 31, + EUN = 32, EAST_UP_NORTH = 32, + WUN = 33, WEST_UP_NORTH = 33, + EDN = 34, EAST_DOWN_NORTH = 34, + WDN = 35, WEST_DOWN_NORTH = 35, + UEN = 36, UP_EAST_NORTH = 36, + DEN = 37, DOWN_EAST_NORTH = 37, + UWN = 38, UP_WEST_NORTH = 38, + DWN = 39, DOWN_WEST_NORTH = 39, + EUS = 40, EAST_UP_SOUTH = 40, + WUS = 41, WEST_UP_SOUTH = 41, + EDS = 42, EAST_DOWN_SOUTH = 42, + WDS = 43, WEST_DOWN_SOUTH = 43, + UES = 44, UP_EAST_SOUTH = 44, + DES = 45, DOWN_EAST_SOUTH = 45, + UWS = 46, UP_WEST_SOUTH = 46, + DWS = 47, DOWN_WEST_SOUTH = 47, END_TRANSFORM = 47 + }; + + // Individual axis enum values indicate which axis an implicit individual + // axis will be mapped to. + // The value of the enum paired with an axis provides the information + // about what the axis will transform to. + // Three individual axis values, one for each axis, are equivalent to one + // ATR enum value, but easier to work with because they are independent. + // Converting to and from the individual axis values from the ATR value + // is a convenient way to implement tranformation related functionality. + // Enum meanings: + // PX: map to positive x axis + // NX: map to negative x axis + // PY: map to positive y axis + // NY: map to negative y axis + // PZ: map to positive z axis + // NZ: map to negative z axis + enum INDIVIDUAL_AXIS { + PX = 0, + NX = 1, + PY = 2, + NY = 3, + PZ = 4, + NZ = 5 + }; + + inline axis_transformation() : atr_(NULL_TRANSFORM) {} + inline axis_transformation(ATR atr) : atr_(atr) {} + inline axis_transformation(const axis_transformation& atr) : atr_(atr.atr_) {} + explicit axis_transformation(const orientation_3d& orient); + explicit axis_transformation(const direction_3d& dir); + explicit axis_transformation(const orientation_2d& orient); + explicit axis_transformation(const direction_2d& dir); + + // assignment operator + axis_transformation& operator=(const axis_transformation& a); + + // assignment operator + axis_transformation& operator=(const ATR& atr); + + // equivalence operator + bool operator==(const axis_transformation& a) const; + + // inequivalence operator + bool operator!=(const axis_transformation& a) const; + + // ordering + bool operator<(const axis_transformation& a) const; + + // concatenation operator + axis_transformation operator+(const axis_transformation& a) const; + + // concatenate this with that + axis_transformation& operator+=(const axis_transformation& a); + + // populate_axis_array writes the three INDIVIDUAL_AXIS values that the + // ATR enum value of 'this' represent into axis_array + void populate_axis_array(INDIVIDUAL_AXIS axis_array[]) const; + + // it is recommended that the directions stored in an array + // in the caller code for easier isotropic access by orientation value + inline void get_directions(direction_2d& horizontal_dir, + direction_2d& vertical_dir) const { + bool bit2 = (atr_ & 4) != 0; + bool bit1 = (atr_ & 2) != 0; + bool bit0 = (atr_ & 1) != 0; + vertical_dir = direction_2d((direction_2d_enum)(((int)(!bit2) << 1) + !bit1)); + horizontal_dir = direction_2d((direction_2d_enum)(((int)(bit2) << 1) + !bit0)); + } + + // it is recommended that the directions stored in an array + // in the caller code for easier isotropic access by orientation value + inline void get_directions(direction_3d& horizontal_dir, + direction_3d& vertical_dir, + direction_3d& proximal_dir) const { + bool bit5 = (atr_ & 32) != 0; + bool bit4 = (atr_ & 16) != 0; + bool bit3 = (atr_ & 8) != 0; + bool bit2 = (atr_ & 4) != 0; + bool bit1 = (atr_ & 2) != 0; + bool bit0 = (atr_ & 1) != 0; + proximal_dir = direction_3d((direction_2d_enum)((((int)(!bit4 & !bit5)) << 2) + + ((int)(bit5) << 1) + + !bit3)); + vertical_dir = direction_3d((direction_2d_enum)((((int)((bit4 & bit2) | (bit5 & !bit2))) << 2)+ + ((int)(!bit5 & !bit2) << 1) + + !bit1)); + horizontal_dir = direction_3d((direction_2d_enum)((((int)((bit5 & bit2) | + (bit4 & !bit2))) << 2) + + ((int)(bit2 & !bit5) << 1) + + !bit0)); + } + + // combine_axis_arrays concatenates this_array and that_array overwriting + // the result into this_array + static void combine_axis_arrays (INDIVIDUAL_AXIS this_array[], + const INDIVIDUAL_AXIS that_array[]); + + // write_back_axis_array converts an array of three INDIVIDUAL_AXIS values + // to the ATR enum value and sets 'this' to that value + void write_back_axis_array(const INDIVIDUAL_AXIS this_array[]); + + // behavior is deterministic but undefined in the case where illegal + // combinations of directions are passed in. + axis_transformation& set_directions(const direction_2d& horizontal_dir, + const direction_2d& vertical_dir); + // behavior is deterministic but undefined in the case where illegal + // combinations of directions are passed in. + axis_transformation& set_directions(const direction_3d& horizontal_dir, + const direction_3d& vertical_dir, + const direction_3d& proximal_dir); + + // transform the two coordinates by reference using the 2D portion of this + template <typename coordinate_type> + void transform(coordinate_type& x, coordinate_type& y) const; + + // transform the three coordinates by reference + template <typename coordinate_type> + void transform(coordinate_type& x, coordinate_type& y, coordinate_type& z) const; + + // invert the 2D portion of this + axis_transformation& invert_2d(); + + // get the inverse of the 2D portion of this + axis_transformation inverse_2d() const; + + // invert this axis_transformation + axis_transformation& invert(); + + // get the inverse axis_transformation of this + axis_transformation inverse() const; + + //friend std::ostream& operator<< (std::ostream& o, const axis_transformation& r); + //friend std::istream& operator>> (std::istream& i, axis_transformation& r); + +private: + ATR atr_; +}; + + +// Scaling object to be used to store the scale factor for each axis + +// For use by the transformation object, in that context the scale factor +// is the amount that each axis scales by when transformed. +// If the horizontal value of the Scale is 10 that means the horizontal +// axis of the input is multiplied by 10 when the transformation is applied. +template <typename scale_factor_type> +class anisotropic_scale_factor { +public: + inline anisotropic_scale_factor() +#ifndef BOOST_POLYGON_MSVC + : scale_() +#endif + { + scale_[0] = 1; + scale_[1] = 1; + scale_[2] = 1; + } + inline anisotropic_scale_factor(scale_factor_type xscale, scale_factor_type yscale) +#ifndef BOOST_POLYGON_MSVC + : scale_() +#endif + { + scale_[0] = xscale; + scale_[1] = yscale; + scale_[2] = 1; + } + inline anisotropic_scale_factor(scale_factor_type xscale, scale_factor_type yscale, scale_factor_type zscale) +#ifndef BOOST_POLYGON_MSVC + : scale_() +#endif + { + scale_[0] = xscale; + scale_[1] = yscale; + scale_[2] = zscale; + } + + // get a component of the anisotropic_scale_factor by orientation + scale_factor_type get(orientation_3d orient) const; + scale_factor_type get(orientation_2d orient) const { return get(orientation_3d(orient)); } + + // set a component of the anisotropic_scale_factor by orientation + void set(orientation_3d orient, scale_factor_type value); + void set(orientation_2d orient, scale_factor_type value) { set(orientation_3d(orient), value); } + + scale_factor_type x() const; + scale_factor_type y() const; + scale_factor_type z() const; + void x(scale_factor_type value); + void y(scale_factor_type value); + void z(scale_factor_type value); + + // concatination operator (convolve scale factors) + anisotropic_scale_factor operator+(const anisotropic_scale_factor& s) const; + + // concatinate this with that + const anisotropic_scale_factor& operator+=(const anisotropic_scale_factor& s); + + // transform this scale with an axis_transform + anisotropic_scale_factor& transform(axis_transformation atr); + + // scale the two coordinates + template <typename coordinate_type> + void scale(coordinate_type& x, coordinate_type& y) const; + + // scale the three coordinates + template <typename coordinate_type> + void scale(coordinate_type& x, coordinate_type& y, coordinate_type& z) const; + + // invert this scale factor to give the reverse scale factor + anisotropic_scale_factor& invert(); + +private: + scale_factor_type scale_[3]; + + //friend std::ostream& operator<< (std::ostream& o, const Scale& r); + //friend std::istream& operator>> (std::istream& i, Scale& r); +}; + +// Transformation object, stores and provides services for transformations + +// Transformation object stores an axistransformation, a scale factor and a translation. +// The tranlation is the position of the origin of the new system of coordinates in the old system. +// The scale scales the coordinates before they are transformed. +template <typename coordinate_type> +class transformation { +public: + transformation(); + transformation(axis_transformation atr); + transformation(axis_transformation::ATR atr); + template <typename point_type> + transformation(const point_type& p); + template <typename point_type> + transformation(axis_transformation atr, const point_type& p); + template <typename point_type> + transformation(axis_transformation atr, const point_type& referencePt, const point_type& destinationPt); + transformation(const transformation& tr); + + // equivalence operator + bool operator==(const transformation& tr) const; + + // inequivalence operator + bool operator!=(const transformation& tr) const; + + // ordering + bool operator<(const transformation& tr) const; + + // concatenation operator + transformation operator+(const transformation& tr) const; + + // concatenate this with that + const transformation& operator+=(const transformation& tr); + + // get the axis_transformation portion of this + inline axis_transformation get_axis_transformation() const {return atr_;} + + // set the axis_transformation portion of this + void set_axis_transformation(const axis_transformation& atr); + + // get the translation portion of this as a point3d + template <typename point_type> + void get_translation(point_type& translation) const; + + // set the translation portion of this with a point3d + template <typename point_type> + void set_translation(const point_type& p); + + // apply the 2D portion of this transformation to the two coordinates given + void transform(coordinate_type& x, coordinate_type& y) const; + + // apply this transformation to the three coordinates given + void transform(coordinate_type& x, coordinate_type& y, coordinate_type& z) const; + + // invert this transformation + transformation& invert(); + + // get the inverse of this transformation + transformation inverse() const; + + inline void get_directions(direction_2d& horizontal_dir, + direction_2d& vertical_dir) const { + return atr_.get_directions(horizontal_dir, vertical_dir); } + + inline void get_directions(direction_3d& horizontal_dir, + direction_3d& vertical_dir, + direction_3d& proximal_dir) const { + return atr_.get_directions(horizontal_dir, vertical_dir, proximal_dir); } + +private: + axis_transformation atr_; + point_3d_data<coordinate_type> p_; + + template <typename point_type> + void construct_dispatch(axis_transformation atr, point_type p, point_concept tag); + template <typename point_type> + void construct_dispatch(axis_transformation atr, point_type p, point_3d_concept tag); + template <typename point_type> + void construct_dispatch(axis_transformation atr, point_type rp, point_type dp, point_concept tag); + template <typename point_type> + void construct_dispatch(axis_transformation atr, point_type rp, point_type dp, point_3d_concept tag); + + //friend std::ostream& operator<< (std::ostream& o, const transformation& tr); + //friend std::istream& operator>> (std::istream& i, transformation& tr); +}; +} +} +#include "detail/transform_detail.hpp" +#endif + |