Chris@16: /* Chris@16: Copyright 2008 Intel Corporation Chris@16: Chris@16: Use, modification and distribution are subject to the Boost Software License, Chris@16: Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: http://www.boost.org/LICENSE_1_0.txt). Chris@16: */ Chris@16: #include Chris@16: #include Chris@16: #ifndef BOOST_POLYGON_POLYGON_FORMATION_HPP Chris@16: #define BOOST_POLYGON_POLYGON_FORMATION_HPP Chris@16: namespace boost { namespace polygon{ Chris@16: Chris@16: namespace polygon_formation { Chris@16: Chris@16: /* Chris@16: * End has two states, HEAD and TAIL as is represented by a bool Chris@16: */ Chris@16: typedef bool End; Chris@16: Chris@16: /* Chris@16: * HEAD End is represented as false because it is the lesser state Chris@16: */ Chris@16: const End HEAD = false; Chris@16: Chris@16: /* Chris@16: * TAIL End is represented by true because TAIL comes after head and 1 after 0 Chris@16: */ Chris@16: const End TAIL = true; Chris@16: Chris@16: /* Chris@16: * 2D turning direction, left and right sides (is a boolean value since it has two states.) Chris@16: */ Chris@16: typedef bool Side; Chris@16: Chris@16: /* Chris@16: * LEFT Side is 0 because we inuitively think left to right; left < right Chris@16: */ Chris@16: const Side LEFT = false; Chris@16: Chris@16: /* Chris@16: * RIGHT Side is 1 so that right > left Chris@16: */ Chris@16: const Side RIGHT = true; Chris@16: Chris@16: /* Chris@16: * The PolyLine class is data storage and services for building and representing partial polygons. Chris@16: * As the polyline is added to it extends its storage to accomodate the data. Chris@16: * PolyLines can be joined head-to-head/head-to-tail when it is determined that two polylines are Chris@16: * part of the same polygon. Chris@16: * PolyLines keep state information about what orientation their incomplete head and tail geometry have, Chris@16: * which side of the polyline is solid and whether the polyline is joined head-to-head and tail-to-head. Chris@16: * PolyLines have nothing whatsoever to do with holes. Chris@16: * It may be valuable to collect a histogram of PolyLine lengths used by an algorithm on its typical data Chris@16: * sets and tune the allocation of the initial vector of coordinate data to be greater than or equal to Chris@16: * the mean, median, mode, or mean plus some number of standard deviation, or just generally large enough Chris@16: * to prevent too much unnecesary reallocations, but not too big that it wastes a lot of memory and degrades cache Chris@16: * performance. Chris@16: */ Chris@16: template Chris@16: class PolyLine { Chris@16: private: Chris@16: //data Chris@16: Chris@16: /* Chris@16: * ptdata_ a vector of coordiantes Chris@16: * if VERTICAL_HEAD, first coordiante is an X Chris@16: * else first coordinate is a Y Chris@16: */ Chris@16: std::vector ptdata_; Chris@16: Chris@16: /* Chris@16: * head and tail points to other polylines before and after this in a chain Chris@16: */ Chris@16: PolyLine* headp_; Chris@16: PolyLine* tailp_; Chris@16: Chris@16: /* Chris@16: * state bitmask Chris@16: * bit zero is orientation, 0 H, 1 V Chris@16: * bit 1 is head connectivity, 0 for head, 1 for tail Chris@16: * bit 2 is tail connectivity, 0 for head, 1 for tail Chris@16: * bit 3 is solid to left of PolyLine when 1, right when 0 Chris@16: */ Chris@16: int state_; Chris@16: Chris@16: public: Chris@16: /* Chris@16: * default constructor (for preallocation) Chris@16: */ Chris@16: PolyLine(); Chris@16: Chris@16: /* Chris@16: * constructor that takes the orientation, coordiante and side to which there is solid Chris@16: */ Chris@16: PolyLine(orientation_2d orient, Unit coord, Side side); Chris@16: Chris@16: //copy constructor Chris@16: PolyLine(const PolyLine& pline); Chris@16: Chris@16: //destructor Chris@16: ~PolyLine(); Chris@16: Chris@16: //assignment operator Chris@16: PolyLine& operator=(const PolyLine& that); Chris@16: Chris@16: //equivalence operator Chris@16: bool operator==(const PolyLine& b) const; Chris@16: Chris@16: /* Chris@16: * valid PolyLine (only default constructed polylines are invalid.) Chris@16: */ Chris@16: bool isValid() const; Chris@16: Chris@16: /* Chris@16: * Orientation of Head Chris@16: */ Chris@16: orientation_2d headOrient() const; Chris@16: Chris@16: /* Chris@16: * returns true if first coordinate is an X value (first segment is vertical) Chris@16: */ Chris@16: bool verticalHead() const; Chris@16: Chris@16: /* Chris@16: * returns the orientation_2d fo the tail Chris@16: */ Chris@16: orientation_2d tailOrient() const; Chris@16: Chris@16: /* Chris@16: * returns true if last coordinate is an X value (last segment is vertical) Chris@16: */ Chris@16: bool verticalTail() const; Chris@16: Chris@16: /* Chris@16: * retrun true if PolyLine has odd number of coordiantes Chris@16: */ Chris@16: bool oddLength() const; Chris@16: Chris@16: /* Chris@16: * retrun the End of the other polyline that the specified end of this polyline is connected to Chris@16: */ Chris@16: End endConnectivity(End end) const; Chris@16: Chris@16: /* Chris@16: * retrun true if the head of this polyline is connect to the tail of a polyline Chris@16: */ Chris@16: bool headToTail() const; Chris@16: /* Chris@16: * retrun true if the head of this polyline is connect to the head of a polyline Chris@16: */ Chris@16: bool headToHead() const; Chris@16: Chris@16: /* Chris@16: * retrun true if the tail of this polyline is connect to the tail of a polyline Chris@16: */ Chris@16: bool tailToTail() const; Chris@16: /* Chris@16: * retrun true if the tail of this polyline is connect to the head of a polyline Chris@16: */ Chris@16: bool tailToHead() const; Chris@16: Chris@16: /* Chris@16: * retrun the side on which there is solid for this polyline Chris@16: */ Chris@16: Side solidSide() const; Chris@16: Chris@16: /* Chris@16: * retrun true if there is solid to the right of this polyline Chris@16: */ Chris@16: bool solidToRight() const; Chris@16: Chris@16: /* Chris@16: * returns true if the polyline tail is not connected Chris@16: */ Chris@16: bool active() const; Chris@16: Chris@16: /* Chris@16: * adds a coordinate value to the end of the polyline changing the tail orientation Chris@16: */ Chris@16: PolyLine& pushCoordinate(Unit coord); Chris@16: Chris@16: /* Chris@16: * removes a coordinate value at the end of the polyline changing the tail orientation Chris@16: */ Chris@16: PolyLine& popCoordinate(); Chris@16: Chris@16: /* Chris@16: * extends the tail of the polyline to include the point, changing orientation if needed Chris@16: */ Chris@16: PolyLine& pushPoint(const point_data& point); Chris@16: Chris@16: /* Chris@16: * changes the last coordinate of the tail of the polyline by the amount of the delta Chris@16: */ Chris@16: PolyLine& extendTail(Unit delta); Chris@16: Chris@16: /* Chris@16: * join thisEnd of this polyline to that polyline's end Chris@16: */ Chris@16: PolyLine& joinTo(End thisEnd, PolyLine& that, End end); Chris@16: Chris@16: /* Chris@16: * join an end of this polyline to the tail of that polyline Chris@16: */ Chris@16: PolyLine& joinToTail(PolyLine& that, End end); Chris@16: Chris@16: /* Chris@16: * join an end of this polyline to the head of that polyline Chris@16: */ Chris@16: PolyLine& joinToHead(PolyLine& that, End end); Chris@16: Chris@16: /* Chris@16: * join the head of this polyline to the head of that polyline Chris@16: */ Chris@16: //join this to that in the given way Chris@16: PolyLine& joinHeadToHead(PolyLine& that); Chris@16: Chris@16: /* Chris@16: * join the head of this polyline to the tail of that polyline Chris@16: */ Chris@16: PolyLine& joinHeadToTail(PolyLine& that); Chris@16: Chris@16: /* Chris@16: * join the tail of this polyline to the head of that polyline Chris@16: */ Chris@16: PolyLine& joinTailToHead(PolyLine& that); Chris@16: Chris@16: /* Chris@16: * join the tail of this polyline to the tail of that polyline Chris@16: */ Chris@16: PolyLine& joinTailToTail(PolyLine& that); Chris@16: Chris@16: /* Chris@16: * dissconnect the tail at the end of the polygon Chris@16: */ Chris@16: PolyLine& disconnectTails(); Chris@16: Chris@16: /* Chris@16: * get the coordinate at one end of this polyline, by default the tail end Chris@16: */ Chris@16: Unit getEndCoord(End end = TAIL) const; Chris@16: Chris@16: /* Chris@16: * get the point on the polyline at the given index (polylines have the same number of coordinates as points Chris@16: */ Chris@16: point_data getPoint(unsigned int index) const; Chris@16: Chris@16: /* Chris@16: * get the point on one end of the polyline, by default the tail Chris@16: */ Chris@16: point_data getEndPoint(End end = TAIL) const; Chris@16: Chris@16: /* Chris@16: * get the orientation of a segment by index Chris@16: */ Chris@16: orientation_2d segmentOrient(unsigned int index = 0) const; Chris@16: Chris@16: /* Chris@16: * get a coordinate by index using the square bracket operator Chris@16: */ Chris@16: Unit operator[] (unsigned int index) const; Chris@16: Chris@16: /* Chris@16: * get the number of segments/points/coordinates in the polyline Chris@16: */ Chris@16: unsigned int numSegments() const; Chris@16: Chris@16: /* Chris@16: * get the pointer to the next polyline at one end of this Chris@16: */ Chris@16: PolyLine* next(End end) const; Chris@16: Chris@16: /* Chris@16: * write out coordinates of this and all attached polylines to a single vector Chris@16: */ Chris@16: PolyLine* writeOut(std::vector& outVec, End startEnd = TAIL) const; Chris@16: Chris@16: private: Chris@16: //methods Chris@16: PolyLine& joinTo_(End thisEnd, PolyLine& that, End end); Chris@16: }; Chris@16: Chris@16: //forward declaration Chris@16: template Chris@16: class PolyLinePolygonData; Chris@16: Chris@16: //forward declaration Chris@16: template Chris@16: class PolyLinePolygonWithHolesData; Chris@16: Chris@16: /* Chris@16: * ActiveTail represents an edge of an incomplete polygon. Chris@16: * Chris@16: * An ActiveTail object is the active tail end of a polyline object, which may (should) be the attached to Chris@16: * a chain of polyline objects through a pointer. The ActiveTail class provides an abstraction between Chris@16: * and algorithm that builds polygons and the PolyLine data representation of incomplete polygons that are Chris@16: * being built. It does this by providing an iterface to access the information about the last edge at the Chris@16: * tail of the PolyLine it is associated with. To a polygon constructing algorithm, an ActiveTail is a floating Chris@16: * edge of an incomplete polygon and has an orientation and coordinate value, as well as knowing which side of Chris@16: * that edge is supposed to be solid or space. Any incomplete polygon will have two active tails. Active tails Chris@16: * may be joined together to merge two incomplete polygons into a larger incomplete polygon. If two active tails Chris@16: * that are to be merged are the oppositve ends of the same incomplete polygon that indicates that the polygon Chris@16: * has been closed and is complete. The active tail keeps a pointer to the other active tail of its incomplete Chris@16: * polygon so that it is easy to check this condition. These pointers are updated when active tails are joined. Chris@16: * The active tail also keeps a list of pointers to active tail objects that serve as handles to closed holes. In Chris@16: * this way a hole can be associated to another incomplete polygon, which will eventually be its enclosing shell, Chris@16: * or reassociate the hole to another incomplete polygon in the case that it become a hole itself. Alternately, Chris@16: * the active tail may add a filiment to stitch a hole into a shell and "fracture" the hole out of the interior Chris@16: * of a polygon. The active tail maintains a static output buffer to temporarily write polygon data to when Chris@16: * it outputs a figure so that outputting a polygon does not require the allocation of a temporary buffer. This Chris@16: * static buffer should be destroyed whenever the program determines that it won't need it anymore and would prefer to Chris@16: * release the memory it has allocated back to the system. Chris@16: */ Chris@16: template Chris@16: class ActiveTail { Chris@16: private: Chris@16: //data Chris@16: PolyLine* tailp_; Chris@16: ActiveTail *otherTailp_; Chris@16: std::list holesList_; Chris@16: //Sum of all the polylines which constitute the active tail (including holes)// Chris@16: size_t polyLineSize_; Chris@16: public: Chris@16: Chris@16: inline size_t getPolyLineSize(){ Chris@16: return polyLineSize_; Chris@16: } Chris@16: Chris@16: inline void setPolyLineSize(int delta){ Chris@16: polyLineSize_ = delta; Chris@16: } Chris@16: Chris@16: inline void addPolyLineSize(int delta){ Chris@16: polyLineSize_ += delta; Chris@16: } Chris@16: Chris@16: /* Chris@16: * iterator over coordinates of the figure Chris@16: */ Chris@16: class iterator { Chris@16: private: Chris@16: const PolyLine* pLine_; Chris@16: const PolyLine* pLineEnd_; Chris@16: unsigned int index_; Chris@16: unsigned int indexEnd_; Chris@16: End startEnd_; Chris@16: public: Chris@16: inline iterator() : pLine_(), pLineEnd_(), index_(), indexEnd_(), startEnd_() {} Chris@16: inline iterator(const ActiveTail* at, bool isHole, orientation_2d orient) : Chris@16: pLine_(), pLineEnd_(), index_(), indexEnd_(), startEnd_() { Chris@16: //if it is a hole and orientation is vertical or it is not a hole and orientation is horizontal Chris@16: //we want to use this active tail, otherwise we want to use the other active tail Chris@16: startEnd_ = TAIL; Chris@16: if(!isHole ^ (orient == HORIZONTAL)) { Chris@16: //switch winding direction Chris@16: at = at->getOtherActiveTail(); Chris@16: } Chris@16: //now we have the right winding direction Chris@16: //if it is horizontal we need to skip the first element Chris@16: pLine_ = at->getTail(); Chris@16: Chris@16: if(at->getTail()->numSegments() > 0) Chris@16: index_ = at->getTail()->numSegments() - 1; Chris@16: Chris@16: if((at->getOrient() == HORIZONTAL) ^ (orient == HORIZONTAL)) { Chris@16: pLineEnd_ = at->getTail(); Chris@16: indexEnd_ = pLineEnd_->numSegments() - 1; Chris@16: if(index_ == 0) { Chris@16: pLine_ = at->getTail()->next(HEAD); Chris@16: if(at->getTail()->endConnectivity(HEAD) == TAIL) { Chris@16: index_ = pLine_->numSegments() -1; Chris@16: } else { Chris@16: startEnd_ = HEAD; Chris@16: index_ = 0; Chris@16: } Chris@16: } else { --index_; } Chris@16: } else { Chris@16: pLineEnd_ = at->getOtherActiveTail()->getTail(); Chris@16: if(pLineEnd_->numSegments() > 0) Chris@16: indexEnd_ = pLineEnd_->numSegments() - 1; Chris@16: } Chris@16: at->getTail()->joinTailToTail(*(at->getOtherActiveTail()->getTail())); Chris@16: } Chris@16: Chris@16: inline size_t size(void){ Chris@16: size_t count = 0; Chris@16: End dir = startEnd_; Chris@16: PolyLine const * currLine = pLine_; Chris@16: size_t ops = 0; Chris@16: while(currLine != pLineEnd_){ Chris@16: ops++; Chris@16: count += currLine->numSegments(); Chris@16: currLine = currLine->next(dir == HEAD ? TAIL : HEAD); Chris@16: dir = currLine->endConnectivity(dir == HEAD ? TAIL : HEAD); Chris@16: } Chris@16: count += pLineEnd_->numSegments(); Chris@16: return count; //no. of vertices Chris@16: } Chris@16: Chris@16: //use bitwise copy and assign provided by the compiler Chris@16: inline iterator& operator++() { Chris@16: if(pLine_ == pLineEnd_ && index_ == indexEnd_) { Chris@16: pLine_ = 0; Chris@16: index_ = 0; Chris@16: return *this; Chris@16: } Chris@16: if(startEnd_ == HEAD) { Chris@16: ++index_; Chris@16: if(index_ == pLine_->numSegments()) { Chris@16: End end = pLine_->endConnectivity(TAIL); Chris@16: pLine_ = pLine_->next(TAIL); Chris@16: if(end == TAIL) { Chris@16: startEnd_ = TAIL; Chris@16: index_ = pLine_->numSegments() -1; Chris@16: } else { Chris@16: index_ = 0; Chris@16: } Chris@16: } Chris@16: } else { Chris@16: if(index_ == 0) { Chris@16: End end = pLine_->endConnectivity(HEAD); Chris@16: pLine_ = pLine_->next(HEAD); Chris@16: if(end == TAIL) { Chris@16: index_ = pLine_->numSegments() -1; Chris@16: } else { Chris@16: startEnd_ = HEAD; Chris@16: index_ = 0; Chris@16: } Chris@16: } else { Chris@16: --index_; Chris@16: } Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: inline const iterator operator++(int) { Chris@16: iterator tmp(*this); Chris@16: ++(*this); Chris@16: return tmp; Chris@16: } Chris@16: inline bool operator==(const iterator& that) const { Chris@16: return pLine_ == that.pLine_ && index_ == that.index_; Chris@16: } Chris@16: inline bool operator!=(const iterator& that) const { Chris@16: return pLine_ != that.pLine_ || index_ != that.index_; Chris@16: } Chris@16: inline Unit operator*() { return (*pLine_)[index_]; } Chris@16: }; Chris@16: Chris@16: /* Chris@16: * iterator over holes contained within the figure Chris@16: */ Chris@16: typedef typename std::list::const_iterator iteratorHoles; Chris@16: Chris@16: //default constructor Chris@16: ActiveTail(); Chris@16: Chris@16: //constructor Chris@16: ActiveTail(orientation_2d orient, Unit coord, Side solidToRight, ActiveTail* otherTailp); Chris@16: Chris@16: //constructor Chris@16: ActiveTail(PolyLine* active, ActiveTail* otherTailp); Chris@16: Chris@16: //copy constructor Chris@16: ActiveTail(const ActiveTail& that); Chris@16: Chris@16: //destructor Chris@16: ~ActiveTail(); Chris@16: Chris@16: //assignment operator Chris@16: ActiveTail& operator=(const ActiveTail& that); Chris@16: Chris@16: //equivalence operator Chris@16: bool operator==(const ActiveTail& b) const; Chris@16: Chris@16: /* Chris@16: * comparison operators, ActiveTail objects are sortable by geometry Chris@16: */ Chris@16: bool operator<(const ActiveTail& b) const; Chris@16: bool operator<=(const ActiveTail& b) const; Chris@16: bool operator>(const ActiveTail& b) const; Chris@16: bool operator>=(const ActiveTail& b) const; Chris@16: Chris@16: /* Chris@16: * get the pointer to the polyline that this is an active tail of Chris@16: */ Chris@16: PolyLine* getTail() const; Chris@16: Chris@16: /* Chris@16: * get the pointer to the polyline at the other end of the chain Chris@16: */ Chris@16: PolyLine* getOtherTail() const; Chris@16: Chris@16: /* Chris@16: * get the pointer to the activetail at the other end of the chain Chris@16: */ Chris@16: ActiveTail* getOtherActiveTail() const; Chris@16: Chris@16: /* Chris@16: * test if another active tail is the other end of the chain Chris@16: */ Chris@16: bool isOtherTail(const ActiveTail& b); Chris@16: Chris@16: /* Chris@16: * update this end of chain pointer to new polyline Chris@16: */ Chris@16: ActiveTail& updateTail(PolyLine* newTail); Chris@16: Chris@16: /* Chris@16: * associate a hole to this active tail by the specified policy Chris@16: */ Chris@16: ActiveTail* addHole(ActiveTail* hole, bool fractureHoles); Chris@16: Chris@16: /* Chris@16: * get the list of holes Chris@16: */ Chris@16: const std::list& getHoles() const; Chris@16: Chris@16: /* Chris@16: * copy holes from that to this Chris@16: */ Chris@16: void copyHoles(ActiveTail& that); Chris@16: Chris@16: /* Chris@16: * find out if solid to right Chris@16: */ Chris@16: bool solidToRight() const; Chris@16: Chris@16: /* Chris@16: * get coordinate (getCoord and getCoordinate are aliases for eachother) Chris@16: */ Chris@16: Unit getCoord() const; Chris@16: Unit getCoordinate() const; Chris@16: Chris@16: /* Chris@16: * get the tail orientation Chris@16: */ Chris@16: orientation_2d getOrient() const; Chris@16: Chris@16: /* Chris@16: * add a coordinate to the polygon at this active tail end, properly handle degenerate edges by removing redundant coordinate Chris@16: */ Chris@16: void pushCoordinate(Unit coord); Chris@16: Chris@16: /* Chris@16: * write the figure that this active tail points to out to the temp buffer Chris@16: */ Chris@16: void writeOutFigure(std::vector& outVec, bool isHole = false) const; Chris@16: Chris@16: /* Chris@16: * write the figure that this active tail points to out through iterators Chris@16: */ Chris@16: void writeOutFigureItrs(iterator& beginOut, iterator& endOut, bool isHole = false, orientation_2d orient = VERTICAL) const; Chris@16: iterator begin(bool isHole, orientation_2d orient) const; Chris@16: iterator end() const; Chris@16: Chris@16: /* Chris@16: * write the holes that this active tail points to out through iterators Chris@16: */ Chris@16: void writeOutFigureHoleItrs(iteratorHoles& beginOut, iteratorHoles& endOut) const; Chris@16: iteratorHoles beginHoles() const; Chris@16: iteratorHoles endHoles() const; Chris@16: Chris@16: /* Chris@16: * joins the two chains that the two active tail tails are ends of Chris@16: * checks for closure of figure and writes out polygons appropriately Chris@16: * returns a handle to a hole if one is closed Chris@16: */ Chris@16: static ActiveTail* joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, std::vector& outBufferTmp); Chris@16: template Chris@16: static ActiveTail* joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, typename std::vector& outBufferTmp); Chris@16: Chris@16: /* Chris@16: * deallocate temp buffer Chris@16: */ Chris@16: static void destroyOutBuffer(); Chris@16: Chris@16: /* Chris@16: * deallocate all polygon data this active tail points to (deep delete, call only from one of a pair of active tails) Chris@16: */ Chris@16: void destroyContents(); Chris@16: }; Chris@16: Chris@16: /* allocate a polyline object */ Chris@16: template Chris@16: PolyLine* createPolyLine(orientation_2d orient, Unit coord, Side side); Chris@16: Chris@16: /* deallocate a polyline object */ Chris@16: template Chris@16: void destroyPolyLine(PolyLine* pLine); Chris@16: Chris@16: /* allocate an activetail object */ Chris@16: template Chris@16: ActiveTail* createActiveTail(); Chris@16: Chris@16: /* deallocate an activetail object */ Chris@16: template Chris@16: void destroyActiveTail(ActiveTail* aTail); Chris@16: Chris@16: template Chris@16: class PolyLineHoleData { Chris@16: private: Chris@16: ActiveTail* p_; Chris@16: public: Chris@16: typedef Unit coordinate_type; Chris@16: typedef typename ActiveTail::iterator compact_iterator_type; Chris@16: typedef iterator_compact_to_points > iterator_type; Chris@16: inline PolyLineHoleData() : p_(0) {} Chris@16: inline PolyLineHoleData(ActiveTail* p) : p_(p) {} Chris@16: //use default copy and assign Chris@16: inline compact_iterator_type begin_compact() const { return p_->begin(true, (orientT ? VERTICAL : HORIZONTAL)); } Chris@16: inline compact_iterator_type end_compact() const { return p_->end(); } Chris@16: inline iterator_type begin() const { return iterator_type(begin_compact(), end_compact()); } Chris@16: inline iterator_type end() const { return iterator_type(end_compact(), end_compact()); } Chris@16: inline std::size_t size() const { Chris@16: return p_->getPolyLineSize(); Chris@16: } Chris@16: inline ActiveTail* yield() { return p_; } Chris@16: template Chris@16: inline PolyLineHoleData& set(iT inputBegin, iT inputEnd) { Chris@16: return *this; Chris@16: } Chris@16: template Chris@16: inline PolyLineHoleData& set_compact(iT inputBegin, iT inputEnd) { Chris@16: return *this; Chris@16: } Chris@16: Chris@16: }; Chris@16: Chris@16: template Chris@16: class PolyLinePolygonWithHolesData { Chris@16: private: Chris@16: ActiveTail* p_; Chris@16: public: Chris@16: typedef Unit coordinate_type; Chris@16: typedef typename ActiveTail::iterator compact_iterator_type; Chris@16: typedef iterator_compact_to_points > iterator_type; Chris@16: typedef PolyLineHoleData hole_type; Chris@16: typedef typename coordinate_traits::area_type area_type; Chris@16: class iteratorHoles { Chris@16: private: Chris@16: typename ActiveTail::iteratorHoles itr_; Chris@16: public: Chris@16: inline iteratorHoles() : itr_() {} Chris@16: inline iteratorHoles(typename ActiveTail::iteratorHoles itr) : itr_(itr) {} Chris@16: //use bitwise copy and assign provided by the compiler Chris@16: inline iteratorHoles& operator++() { Chris@16: ++itr_; Chris@16: return *this; Chris@16: } Chris@16: inline const iteratorHoles operator++(int) { Chris@16: iteratorHoles tmp(*this); Chris@16: ++(*this); Chris@16: return tmp; Chris@16: } Chris@16: inline bool operator==(const iteratorHoles& that) const { Chris@16: return itr_ == that.itr_; Chris@16: } Chris@16: inline bool operator!=(const iteratorHoles& that) const { Chris@16: return itr_ != that.itr_; Chris@16: } Chris@16: inline PolyLineHoleData operator*() { return PolyLineHoleData(*itr_);} Chris@16: }; Chris@16: typedef iteratorHoles iterator_holes_type; Chris@16: Chris@16: inline PolyLinePolygonWithHolesData() : p_(0) {} Chris@16: inline PolyLinePolygonWithHolesData(ActiveTail* p) : p_(p) {} Chris@16: //use default copy and assign Chris@16: inline compact_iterator_type begin_compact() const { return p_->begin(false, (orientT ? VERTICAL : HORIZONTAL)); } Chris@16: inline compact_iterator_type end_compact() const { return p_->end(); } Chris@16: inline iterator_type begin() const { return iterator_type(begin_compact(), end_compact()); } Chris@16: inline iterator_type end() const { return iterator_type(end_compact(), end_compact()); } Chris@16: inline iteratorHoles begin_holes() const { return iteratorHoles(p_->beginHoles()); } Chris@16: inline iteratorHoles end_holes() const { return iteratorHoles(p_->endHoles()); } Chris@16: inline ActiveTail* yield() { return p_; } Chris@16: //stub out these four required functions that will not be used but are needed for the interface Chris@16: inline std::size_t size_holes() const { return 0; } Chris@16: inline std::size_t size() const { return 0; } Chris@16: template Chris@16: inline PolyLinePolygonWithHolesData& set(iT inputBegin, iT inputEnd) { Chris@16: return *this; Chris@16: } Chris@16: template Chris@16: inline PolyLinePolygonWithHolesData& set_compact(iT inputBegin, iT inputEnd) { Chris@16: return *this; Chris@16: } Chris@16: Chris@16: // initialize a polygon from x,y values, it is assumed that the first is an x Chris@16: // and that the input is a well behaved polygon Chris@16: template Chris@16: inline PolyLinePolygonWithHolesData& set_holes(iT inputBegin, iT inputEnd) { Chris@16: return *this; Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: struct PolyLineType { }; Chris@16: template Chris@16: struct PolyLineType { typedef PolyLinePolygonWithHolesData type; }; Chris@16: template Chris@16: struct PolyLineType { typedef PolyLinePolygonWithHolesData type; }; Chris@16: template Chris@16: struct PolyLineType { typedef PolyLinePolygonWithHolesData type; }; Chris@16: template Chris@16: struct PolyLineType { typedef PolyLineHoleData type; }; Chris@16: template Chris@16: struct PolyLineType { typedef PolyLineHoleData type; }; Chris@16: template Chris@16: struct PolyLineType { typedef PolyLineHoleData type; }; Chris@16: Chris@16: template Chris@16: class ScanLineToPolygonItrs { Chris@16: private: Chris@16: std::map*> tailMap_; Chris@16: typedef typename PolyLineType::type PolyLinePolygonData; Chris@16: std::vector outputPolygons_; Chris@16: bool fractureHoles_; Chris@16: public: Chris@16: typedef typename std::vector::iterator iterator; Chris@16: inline ScanLineToPolygonItrs() : tailMap_(), outputPolygons_(), fractureHoles_(false) {} Chris@16: /* construct a scanline with the proper offsets, protocol and options */ Chris@16: inline ScanLineToPolygonItrs(bool fractureHoles) : tailMap_(), outputPolygons_(), fractureHoles_(fractureHoles) {} Chris@16: Chris@16: ~ScanLineToPolygonItrs() { clearOutput_(); } Chris@16: Chris@16: /* process all vertical edges, left and right, at a unique x coordinate, edges must be sorted low to high */ Chris@16: void processEdges(iterator& beginOutput, iterator& endOutput, Chris@16: Unit currentX, std::vector >& leftEdges, Chris@16: std::vector >& rightEdges, Chris@16: size_t vertexThreshold=(std::numeric_limits::max)() ); Chris@16: Chris@16: /********************************************************************** Chris@16: *methods implementing new polygon formation code Chris@16: * Chris@16: **********************************************************************/ Chris@16: void updatePartialSimplePolygonsWithRightEdges(Unit currentX, Chris@16: const std::vector >& leftEdges, size_t threshold); Chris@16: Chris@16: void updatePartialSimplePolygonsWithLeftEdges(Unit currentX, Chris@16: const std::vector >& leftEdges, size_t threshold); Chris@16: Chris@16: void closePartialSimplePolygon(Unit, ActiveTail*, ActiveTail*); Chris@16: Chris@16: void maintainPartialSimplePolygonInvariant(iterator& ,iterator& ,Unit, Chris@16: const std::vector >&, Chris@16: const std::vector >&, Chris@16: size_t vertexThreshold=(std::numeric_limits::max)()); Chris@16: Chris@16: void insertNewLeftEdgeIntoTailMap(Unit, Unit, Unit, Chris@16: typename std::map*>::iterator &); Chris@16: /**********************************************************************/ Chris@16: Chris@16: inline size_t getTailMapSize(){ Chris@16: typename std::map* >::const_iterator itr; Chris@16: size_t tsize = 0; Chris@16: for(itr=tailMap_.begin(); itr!=tailMap_.end(); ++itr){ Chris@16: tsize += (itr->second)->getPolyLineSize(); Chris@16: } Chris@16: return tsize; Chris@16: } Chris@16: /*print the active tails in this map:*/ Chris@16: inline void print(){ Chris@16: typename std::map* >::const_iterator itr; Chris@16: printf("=========TailMap[%lu]=========\n", tailMap_.size()); Chris@16: for(itr=tailMap_.begin(); itr!=tailMap_.end(); ++itr){ Chris@16: std::cout<< "[" << itr->first << "] : " << std::endl; Chris@16: //print active tail// Chris@16: ActiveTail const *t = (itr->second); Chris@16: PolyLine const *pBegin = t->getTail(); Chris@16: PolyLine const *pEnd = t->getOtherActiveTail()->getTail(); Chris@16: std::string sorient = pBegin->solidToRight() ? "RIGHT" : "LEFT"; Chris@16: std::cout<< " ActiveTail.tailp_ (solid= " << sorient ; Chris@16: End dir = TAIL; Chris@16: while(pBegin!=pEnd){ Chris@16: std::cout << pBegin << "={ "; Chris@16: for(size_t i=0; inumSegments(); i++){ Chris@16: point_data u = pBegin->getPoint(i); Chris@16: std::cout << "(" << u.x() << "," << u.y() << ") "; Chris@16: } Chris@16: std::cout << "} "; Chris@16: pBegin = pBegin->next(dir == HEAD ? TAIL : HEAD); Chris@16: dir = pBegin->endConnectivity(dir == HEAD ? TAIL : HEAD); Chris@16: } Chris@16: if(pEnd){ Chris@16: std::cout << pEnd << "={ "; Chris@16: for(size_t i=0; inumSegments(); i++){ Chris@16: point_data u = pEnd->getPoint(i); Chris@16: std::cout << "(" << u.x() << "," << u.y() << ") "; Chris@16: } Chris@16: std::cout << "} "; Chris@16: } Chris@16: std::cout << " end= " << pEnd << std::endl; Chris@16: } Chris@16: } Chris@16: Chris@16: private: Chris@16: void clearOutput_(); Chris@16: }; Chris@16: Chris@16: /* Chris@16: * ScanLine does all the work of stitching together polygons from incoming vertical edges Chris@16: */ Chris@16: // template Chris@16: // class ScanLineToPolygons { Chris@16: // private: Chris@16: // ScanLineToPolygonItrs scanline_; Chris@16: // public: Chris@16: // inline ScanLineToPolygons() : scanline_() {} Chris@16: // /* construct a scanline with the proper offsets, protocol and options */ Chris@16: // inline ScanLineToPolygons(bool fractureHoles) : scanline_(fractureHoles) {} Chris@16: Chris@16: // /* process all vertical edges, left and right, at a unique x coordinate, edges must be sorted low to high */ Chris@16: // inline void processEdges(std::vector& outBufferTmp, Unit currentX, std::vector >& leftEdges, Chris@16: // std::vector >& rightEdges) { Chris@16: // typename ScanLineToPolygonItrs::iterator itr, endItr; Chris@16: // scanline_.processEdges(itr, endItr, currentX, leftEdges, rightEdges); Chris@16: // //copy data into outBufferTmp Chris@16: // while(itr != endItr) { Chris@16: // typename PolyLinePolygonData::iterator pditr; Chris@16: // outBufferTmp.push_back(0); Chris@16: // unsigned int sizeIndex = outBufferTmp.size() - 1; Chris@16: // int count = 0; Chris@16: // for(pditr = (*itr).begin(); pditr != (*itr).end(); ++pditr) { Chris@16: // outBufferTmp.push_back(*pditr); Chris@16: // ++count; Chris@16: // } Chris@16: // outBufferTmp[sizeIndex] = count; Chris@16: // typename PolyLinePolygonData::iteratorHoles pdHoleItr; Chris@16: // for(pdHoleItr = (*itr).beginHoles(); pdHoleItr != (*itr).endHoles(); ++pdHoleItr) { Chris@16: // outBufferTmp.push_back(0); Chris@16: // unsigned int sizeIndex2 = outBufferTmp.size() - 1; Chris@16: // int count2 = 0; Chris@16: // for(pditr = (*pdHoleItr).begin(); pditr != (*pdHoleItr).end(); ++pditr) { Chris@16: // outBufferTmp.push_back(*pditr); Chris@16: // ++count2; Chris@16: // } Chris@16: // outBufferTmp[sizeIndex2] = -count; Chris@16: // } Chris@16: // ++itr; Chris@16: // } Chris@16: // } Chris@16: // }; Chris@16: Chris@16: const int VERTICAL_HEAD = 1, HEAD_TO_TAIL = 2, TAIL_TO_TAIL = 4, SOLID_TO_RIGHT = 8; Chris@16: Chris@16: //EVERY FUNCTION in this DEF file should be explicitly defined as inline Chris@16: Chris@16: //microsoft compiler improperly warns whenever you cast an integer to bool Chris@16: //call this function on an integer to convert it to bool without a warning Chris@16: template Chris@16: inline bool to_bool(const T& val) { return val != 0; } Chris@16: Chris@16: //default constructor (for preallocation) Chris@16: template Chris@16: inline PolyLine::PolyLine() : ptdata_() ,headp_(0), tailp_(0), state_(-1) {} Chris@16: Chris@16: //constructor Chris@16: template Chris@16: inline PolyLine::PolyLine(orientation_2d orient, Unit coord, Side side) : Chris@16: ptdata_(1, coord), Chris@16: headp_(0), Chris@16: tailp_(0), Chris@16: state_(orient.to_int() + Chris@16: (side << 3)){} Chris@16: Chris@16: //copy constructor Chris@16: template Chris@16: inline PolyLine::PolyLine(const PolyLine& pline) : ptdata_(pline.ptdata_), Chris@16: headp_(pline.headp_), Chris@16: tailp_(pline.tailp_), Chris@16: state_(pline.state_) {} Chris@16: Chris@16: //destructor Chris@16: template Chris@16: inline PolyLine::~PolyLine() { Chris@16: //clear out data just in case it is read later Chris@16: headp_ = tailp_ = 0; Chris@16: state_ = 0; Chris@16: } Chris@16: Chris@16: template Chris@16: inline PolyLine& PolyLine::operator=(const PolyLine& that) { Chris@16: if(!(this == &that)) { Chris@16: headp_ = that.headp_; Chris@16: tailp_ = that.tailp_; Chris@16: ptdata_ = that.ptdata_; Chris@16: state_ = that.state_; Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool PolyLine::operator==(const PolyLine& b) const { Chris@16: return this == &b || (state_ == b.state_ && Chris@16: headp_ == b.headp_ && Chris@16: tailp_ == b.tailp_); Chris@16: } Chris@16: Chris@16: //valid PolyLine Chris@16: template Chris@16: inline bool PolyLine::isValid() const { Chris@16: return state_ > -1; } Chris@16: Chris@16: //first coordinate is an X value Chris@16: //first segment is vertical Chris@16: template Chris@16: inline bool PolyLine::verticalHead() const { Chris@16: return state_ & VERTICAL_HEAD; Chris@16: } Chris@16: Chris@16: //retrun true is PolyLine has odd number of coordiantes Chris@16: template Chris@16: inline bool PolyLine::oddLength() const { Chris@16: return to_bool((ptdata_.size()-1) % 2); Chris@16: } Chris@16: Chris@16: //last coordiante is an X value Chris@16: //last segment is vertical Chris@16: template Chris@16: inline bool PolyLine::verticalTail() const { Chris@16: return to_bool(verticalHead() ^ oddLength()); Chris@16: } Chris@16: Chris@16: template Chris@16: inline orientation_2d PolyLine::tailOrient() const { Chris@16: return (verticalTail() ? VERTICAL : HORIZONTAL); Chris@16: } Chris@16: Chris@16: template Chris@16: inline orientation_2d PolyLine::headOrient() const { Chris@16: return (verticalHead() ? VERTICAL : HORIZONTAL); Chris@16: } Chris@16: Chris@16: template Chris@16: inline End PolyLine::endConnectivity(End end) const { Chris@16: //Tail should be defined as true Chris@16: if(end) { return tailToTail(); } Chris@16: return headToTail(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool PolyLine::headToTail() const { Chris@16: return to_bool(state_ & HEAD_TO_TAIL); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool PolyLine::headToHead() const { Chris@16: return to_bool(!headToTail()); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool PolyLine::tailToHead() const { Chris@16: return to_bool(!tailToTail()); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool PolyLine::tailToTail() const { Chris@16: return to_bool(state_ & TAIL_TO_TAIL); Chris@16: } Chris@16: Chris@16: template Chris@16: inline Side PolyLine::solidSide() const { Chris@16: return solidToRight(); } Chris@16: Chris@16: template Chris@16: inline bool PolyLine::solidToRight() const { Chris@16: return to_bool(state_ & SOLID_TO_RIGHT) != 0; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool PolyLine::active() const { Chris@16: return !to_bool(tailp_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline PolyLine& PolyLine::pushCoordinate(Unit coord) { Chris@16: ptdata_.push_back(coord); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: inline PolyLine& PolyLine::popCoordinate() { Chris@16: ptdata_.pop_back(); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: inline PolyLine& PolyLine::pushPoint(const point_data& point) { Chris@16: if(numSegments()){ Chris@16: point_data endPt = getEndPoint(); Chris@16: //vertical is true, horizontal is false Chris@16: if((tailOrient().to_int() ? point.get(VERTICAL) == endPt.get(VERTICAL) : point.get(HORIZONTAL) == endPt.get(HORIZONTAL))) { Chris@16: //we were pushing a colinear segment Chris@16: return popCoordinate(); Chris@16: } Chris@16: } Chris@16: return pushCoordinate(tailOrient().to_int() ? point.get(VERTICAL) : point.get(HORIZONTAL)); Chris@16: } Chris@16: Chris@16: template Chris@16: inline PolyLine& PolyLine::extendTail(Unit delta) { Chris@16: ptdata_.back() += delta; Chris@16: return *this; Chris@16: } Chris@16: Chris@16: //private member function that creates a link from this PolyLine to that Chris@16: template Chris@16: inline PolyLine& PolyLine::joinTo_(End thisEnd, PolyLine& that, End end) { Chris@16: if(thisEnd){ Chris@16: tailp_ = &that; Chris@16: state_ &= ~TAIL_TO_TAIL; //clear any previous state_ of bit (for safety) Chris@16: state_ |= (end << 2); //place bit into mask Chris@16: } else { Chris@16: headp_ = &that; Chris@16: state_ &= ~HEAD_TO_TAIL; //clear any previous state_ of bit (for safety) Chris@16: state_ |= (end << 1); //place bit into mask Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: Chris@16: //join two PolyLines (both ways of the association) Chris@16: template Chris@16: inline PolyLine& PolyLine::joinTo(End thisEnd, PolyLine& that, End end) { Chris@16: joinTo_(thisEnd, that, end); Chris@16: that.joinTo_(end, *this, thisEnd); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: //convenience functions for joining PolyLines Chris@16: template Chris@16: inline PolyLine& PolyLine::joinToTail(PolyLine& that, End end) { Chris@16: return joinTo(TAIL, that, end); Chris@16: } Chris@16: template Chris@16: inline PolyLine& PolyLine::joinToHead(PolyLine& that, End end) { Chris@16: return joinTo(HEAD, that, end); Chris@16: } Chris@16: template Chris@16: inline PolyLine& PolyLine::joinHeadToHead(PolyLine& that) { Chris@16: return joinToHead(that, HEAD); Chris@16: } Chris@16: template Chris@16: inline PolyLine& PolyLine::joinHeadToTail(PolyLine& that) { Chris@16: return joinToHead(that, TAIL); Chris@16: } Chris@16: template Chris@16: inline PolyLine& PolyLine::joinTailToHead(PolyLine& that) { Chris@16: return joinToTail(that, HEAD); Chris@16: } Chris@16: template Chris@16: inline PolyLine& PolyLine::joinTailToTail(PolyLine& that) { Chris@16: return joinToTail(that, TAIL); Chris@16: } Chris@16: Chris@16: template Chris@16: inline PolyLine& PolyLine::disconnectTails() { Chris@16: next(TAIL)->state_ &= !TAIL_TO_TAIL; Chris@16: next(TAIL)->tailp_ = 0; Chris@16: state_ &= !TAIL_TO_TAIL; Chris@16: tailp_ = 0; Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: inline Unit PolyLine::getEndCoord(End end) const { Chris@16: if(end) Chris@16: return ptdata_.back(); Chris@16: return ptdata_.front(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline orientation_2d PolyLine::segmentOrient(unsigned int index) const { Chris@16: return (to_bool((unsigned int)verticalHead() ^ (index % 2)) ? VERTICAL : HORIZONTAL); Chris@16: } Chris@16: Chris@16: template Chris@16: inline point_data PolyLine::getPoint(unsigned int index) const { Chris@16: //assert(isValid() && headp_->isValid()) ("PolyLine: headp_ must be valid"); Chris@16: point_data pt; Chris@16: pt.set(HORIZONTAL, ptdata_[index]); Chris@16: pt.set(VERTICAL, ptdata_[index]); Chris@16: Unit prevCoord; Chris@16: if(index == 0) { Chris@16: prevCoord = headp_->getEndCoord(headToTail()); Chris@16: } else { Chris@16: prevCoord = ptdata_[index-1]; Chris@16: } Chris@16: pt.set(segmentOrient(index), prevCoord); Chris@16: return pt; Chris@16: } Chris@16: Chris@16: template Chris@16: inline point_data PolyLine::getEndPoint(End end) const { Chris@16: return getPoint((end ? numSegments() - 1 : (unsigned int)0)); Chris@16: } Chris@16: Chris@16: template Chris@16: inline Unit PolyLine::operator[] (unsigned int index) const { Chris@16: //assert(ptdata_.size() > index) ("PolyLine: out of bounds index"); Chris@16: return ptdata_[index]; Chris@16: } Chris@16: Chris@16: template Chris@16: inline unsigned int PolyLine::numSegments() const { Chris@16: return ptdata_.size(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline PolyLine* PolyLine::next(End end) const { Chris@16: return (end ? tailp_ : headp_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline ActiveTail::ActiveTail() : tailp_(0), otherTailp_(0), holesList_(), Chris@16: polyLineSize_(0) {} Chris@16: Chris@16: template Chris@16: inline ActiveTail::ActiveTail(orientation_2d orient, Unit coord, Side solidToRight, ActiveTail* otherTailp) : Chris@16: tailp_(0), otherTailp_(0), holesList_(), polyLineSize_(0) { Chris@16: tailp_ = createPolyLine(orient, coord, solidToRight); Chris@16: otherTailp_ = otherTailp; Chris@16: polyLineSize_ = tailp_->numSegments(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline ActiveTail::ActiveTail(PolyLine* active, ActiveTail* otherTailp) : Chris@16: tailp_(active), otherTailp_(otherTailp), holesList_(), Chris@16: polyLineSize_(0) {} Chris@16: Chris@16: //copy constructor Chris@16: template Chris@16: inline ActiveTail::ActiveTail(const ActiveTail& that) : tailp_(that.tailp_), otherTailp_(that.otherTailp_), holesList_(), polyLineSize_(that.polyLineSize_) {} Chris@16: Chris@16: //destructor Chris@16: template Chris@16: inline ActiveTail::~ActiveTail() { Chris@16: //clear them in case the memory is read later Chris@16: tailp_ = 0; otherTailp_ = 0; Chris@16: } Chris@16: Chris@16: template Chris@16: inline ActiveTail& ActiveTail::operator=(const ActiveTail& that) { Chris@16: //self assignment is safe in this case Chris@16: tailp_ = that.tailp_; Chris@16: otherTailp_ = that.otherTailp_; Chris@16: polyLineSize_ = that.polyLineSize_; Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool ActiveTail::operator==(const ActiveTail& b) const { Chris@16: return tailp_ == b.tailp_ && otherTailp_ == b.otherTailp_; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool ActiveTail::operator<(const ActiveTail& b) const { Chris@16: return tailp_->getEndPoint().get(VERTICAL) < b.tailp_->getEndPoint().get(VERTICAL); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool ActiveTail::operator<=(const ActiveTail& b) const { Chris@16: return !(*this > b); } Chris@16: Chris@16: template Chris@16: inline bool ActiveTail::operator>(const ActiveTail& b) const { Chris@16: return b < (*this); } Chris@16: Chris@16: template Chris@16: inline bool ActiveTail::operator>=(const ActiveTail& b) const { Chris@16: return !(*this < b); } Chris@16: Chris@16: template Chris@16: inline PolyLine* ActiveTail::getTail() const { Chris@16: return tailp_; } Chris@16: Chris@16: template Chris@16: inline PolyLine* ActiveTail::getOtherTail() const { Chris@16: return otherTailp_->tailp_; } Chris@16: Chris@16: template Chris@16: inline ActiveTail* ActiveTail::getOtherActiveTail() const { Chris@16: return otherTailp_; } Chris@16: Chris@16: template Chris@16: inline bool ActiveTail::isOtherTail(const ActiveTail& b) { Chris@16: // assert( (tailp_ == b.getOtherTail() && getOtherTail() == b.tailp_) || Chris@16: // (tailp_ != b.getOtherTail() && getOtherTail() != b.tailp_)) Chris@16: // ("ActiveTail: Active tails out of sync"); Chris@16: return otherTailp_ == &b; Chris@16: } Chris@16: Chris@16: template Chris@16: inline ActiveTail& ActiveTail::updateTail(PolyLine* newTail) { Chris@16: //subtract the old size and add new size// Chris@16: int delta = newTail->numSegments() - tailp_->numSegments(); Chris@16: addPolyLineSize(delta); Chris@16: otherTailp_->addPolyLineSize(delta); Chris@16: tailp_ = newTail; Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template Chris@16: inline ActiveTail* ActiveTail::addHole(ActiveTail* hole, bool fractureHoles) { Chris@16: Chris@16: if(!fractureHoles){ Chris@16: holesList_.push_back(hole); Chris@16: copyHoles(*hole); Chris@16: copyHoles(*(hole->getOtherActiveTail())); Chris@16: return this; Chris@16: } Chris@16: ActiveTail* h, *v; Chris@16: ActiveTail* other = hole->getOtherActiveTail(); Chris@16: if(other->getOrient() == VERTICAL) { Chris@16: //assert that hole.getOrient() == HORIZONTAL Chris@16: //this case should never happen Chris@16: h = hole; Chris@16: v = other; Chris@16: } else { Chris@16: //assert that hole.getOrient() == VERTICAL Chris@16: h = other; Chris@16: v = hole; Chris@16: } Chris@16: h->pushCoordinate(v->getCoordinate()); Chris@16: //assert that h->getOrient() == VERTICAL Chris@16: //v->pushCoordinate(getCoordinate()); Chris@16: //assert that v->getOrient() == VERTICAL Chris@16: //I can't close a figure by adding a hole, so pass zero for xMin and yMin Chris@16: std::vector tmpVec; Chris@16: ActiveTail::joinChains(this, h, false, tmpVec); Chris@16: return v; Chris@16: } Chris@16: Chris@16: template Chris@16: inline const std::list*>& ActiveTail::getHoles() const { Chris@16: return holesList_; Chris@16: } Chris@16: Chris@16: template Chris@16: inline void ActiveTail::copyHoles(ActiveTail& that) { Chris@16: holesList_.splice(holesList_.end(), that.holesList_); //splice the two lists together Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool ActiveTail::solidToRight() const { Chris@16: return getTail()->solidToRight(); } Chris@16: Chris@16: template Chris@16: inline Unit ActiveTail::getCoord() const { Chris@16: return getTail()->getEndCoord(); } Chris@16: Chris@16: template Chris@16: inline Unit ActiveTail::getCoordinate() const { Chris@16: return getCoord(); } Chris@16: Chris@16: template Chris@16: inline orientation_2d ActiveTail::getOrient() const { Chris@16: return getTail()->tailOrient(); } Chris@16: Chris@16: template Chris@16: inline void ActiveTail::pushCoordinate(Unit coord) { Chris@16: //appropriately handle any co-linear polyline segments by calling push point internally Chris@16: point_data p; Chris@16: p.set(HORIZONTAL, coord); Chris@16: p.set(VERTICAL, coord); Chris@16: //if we are vertical assign the last coordinate (an X) to p.x, else to p.y Chris@16: p.set(getOrient().get_perpendicular(), getCoordinate()); Chris@16: int oldSegments = tailp_->numSegments(); Chris@16: tailp_->pushPoint(p); Chris@16: int delta = tailp_->numSegments() - oldSegments; Chris@16: addPolyLineSize(delta); Chris@16: otherTailp_->addPolyLineSize(delta); Chris@16: } Chris@16: Chris@16: Chris@16: //global utility functions Chris@16: template Chris@16: inline PolyLine* createPolyLine(orientation_2d orient, Unit coord, Side side) { Chris@16: return new PolyLine(orient, coord, side); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void destroyPolyLine(PolyLine* pLine) { Chris@16: delete pLine; Chris@16: } Chris@16: Chris@16: template Chris@16: inline ActiveTail* createActiveTail() { Chris@16: //consider replacing system allocator with ActiveTail memory pool Chris@16: return new ActiveTail(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void destroyActiveTail(ActiveTail* aTail) { Chris@16: delete aTail; Chris@16: } Chris@16: Chris@16: Chris@16: //no recursion, to prevent max recursion depth errors Chris@16: template Chris@16: inline void ActiveTail::destroyContents() { Chris@16: tailp_->disconnectTails(); Chris@16: PolyLine* nextPolyLinep = tailp_->next(HEAD); Chris@16: End end = tailp_->endConnectivity(HEAD); Chris@16: destroyPolyLine(tailp_); Chris@16: while(nextPolyLinep) { Chris@16: End nextEnd = nextPolyLinep->endConnectivity(!end); //get the direction of next polyLine Chris@16: PolyLine* nextNextPolyLinep = nextPolyLinep->next(!end); //get the next polyline Chris@16: destroyPolyLine(nextPolyLinep); //destroy the current polyline Chris@16: end = nextEnd; Chris@16: nextPolyLinep = nextNextPolyLinep; Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename ActiveTail::iterator ActiveTail::begin(bool isHole, orientation_2d orient) const { Chris@16: return iterator(this, isHole, orient); Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename ActiveTail::iterator ActiveTail::end() const { Chris@16: return iterator(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename ActiveTail::iteratorHoles ActiveTail::beginHoles() const { Chris@16: return holesList_.begin(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename ActiveTail::iteratorHoles ActiveTail::endHoles() const { Chris@16: return holesList_.end(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void ActiveTail::writeOutFigureItrs(iterator& beginOut, iterator& endOut, bool isHole, orientation_2d orient) const { Chris@16: beginOut = begin(isHole, orient); Chris@16: endOut = end(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void ActiveTail::writeOutFigureHoleItrs(iteratorHoles& beginOut, iteratorHoles& endOut) const { Chris@16: beginOut = beginHoles(); Chris@16: endOut = endHoles(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void ActiveTail::writeOutFigure(std::vector& outVec, bool isHole) const { Chris@16: //we start writing out the polyLine that this active tail points to at its tail Chris@16: std::size_t size = outVec.size(); Chris@16: outVec.push_back(0); //place holder for size Chris@16: PolyLine* nextPolyLinep = 0; Chris@16: if(!isHole){ Chris@16: nextPolyLinep = otherTailp_->tailp_->writeOut(outVec); Chris@16: } else { Chris@16: nextPolyLinep = tailp_->writeOut(outVec); Chris@16: } Chris@16: Unit firsty = outVec[size + 1]; Chris@16: if((getOrient() == HORIZONTAL) ^ !isHole) { Chris@16: //our first coordinate is a y value, so we need to rotate it to the end Chris@16: typename std::vector::iterator tmpItr = outVec.begin(); Chris@16: tmpItr += size; Chris@16: outVec.erase(++tmpItr); //erase the 2nd element Chris@16: } Chris@16: End startEnd = tailp_->endConnectivity(HEAD); Chris@16: if(isHole) startEnd = otherTailp_->tailp_->endConnectivity(HEAD); Chris@16: while(nextPolyLinep) { Chris@16: bool nextStartEnd = nextPolyLinep->endConnectivity(!startEnd); Chris@16: nextPolyLinep = nextPolyLinep->writeOut(outVec, startEnd); Chris@16: startEnd = nextStartEnd; Chris@16: } Chris@16: if((getOrient() == HORIZONTAL) ^ !isHole) { Chris@16: //we want to push the y value onto the end since we ought to have ended with an x Chris@16: outVec.push_back(firsty); //should never be executed because we want first value to be an x Chris@16: } Chris@16: //the vector contains the coordinates of the linked list of PolyLines in the correct order Chris@16: //first element is supposed to be the size Chris@16: outVec[size] = outVec.size() - 1 - size; //number of coordinates in vector Chris@16: //assert outVec[size] % 2 == 0 //it should be even Chris@16: //make the size negative for holes Chris@16: outVec[size] *= (isHole ? -1 : 1); Chris@16: } Chris@16: Chris@16: //no recursion to prevent max recursion depth errors Chris@16: template Chris@16: inline PolyLine* PolyLine::writeOut(std::vector& outVec, End startEnd) const { Chris@16: if(startEnd == HEAD){ Chris@16: //forward order Chris@16: outVec.insert(outVec.end(), ptdata_.begin(), ptdata_.end()); Chris@16: return tailp_; Chris@16: }else{ Chris@16: //reverse order Chris@16: //do not reserve because we expect outVec to be large enough already Chris@16: for(int i = ptdata_.size() - 1; i >= 0; --i){ Chris@16: outVec.push_back(ptdata_[i]); Chris@16: } Chris@16: //NT didn't know about this version of the API.... Chris@16: //outVec.insert(outVec.end(), ptdata_.rbegin(), ptdata_.rend()); Chris@16: return headp_; Chris@16: } Chris@16: } Chris@16: Chris@16: //solid indicates if it was joined by a solit or a space Chris@16: template Chris@16: inline ActiveTail* ActiveTail::joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, std::vector& outBufferTmp) Chris@16: { Chris@16: //checks to see if we closed a figure Chris@16: if(at1->isOtherTail(*at2)){ Chris@16: //value of solid tells us if we closed solid or hole Chris@16: //and output the solid or handle the hole appropriately Chris@16: //if the hole needs to fracture across horizontal partition boundary we need to notify Chris@16: //the calling context to do so Chris@16: if(solid) { Chris@16: //the chains are being joined because there is solid to the right Chris@16: //this means that if the figure is closed at this point it must be a hole Chris@16: //because otherwise it would have to have another vertex to the right of this one Chris@16: //and would not be closed at this point Chris@16: return at1; Chris@16: } else { Chris@16: //assert pG != 0 Chris@16: //the figure that was closed is a shell Chris@16: at1->writeOutFigure(outBufferTmp); Chris@16: //process holes of the polygon Chris@16: at1->copyHoles(*at2); //there should not be holes on at2, but if there are, copy them over Chris@16: const std::list*>& holes = at1->getHoles(); Chris@16: for(typename std::list*>::const_iterator litr = holes.begin(); litr != holes.end(); ++litr) { Chris@16: (*litr)->writeOutFigure(outBufferTmp, true); Chris@16: //delete the hole Chris@16: (*litr)->destroyContents(); Chris@16: destroyActiveTail((*litr)->getOtherActiveTail()); Chris@16: destroyActiveTail((*litr)); Chris@16: } Chris@16: //delete the polygon Chris@16: at1->destroyContents(); Chris@16: //at2 contents are the same as at1, so it should not destroy them Chris@16: destroyActiveTail(at1); Chris@16: destroyActiveTail(at2); Chris@16: } Chris@16: return 0; Chris@16: } Chris@16: //join the two partial polygons into one large partial polygon Chris@16: at1->getTail()->joinTailToTail(*(at2->getTail())); Chris@16: *(at1->getOtherActiveTail()) = ActiveTail(at1->getOtherTail(), at2->getOtherActiveTail()); Chris@16: *(at2->getOtherActiveTail()) = ActiveTail(at2->getOtherTail(), at1->getOtherActiveTail()); Chris@16: Chris@16: int accumulate = at2->getPolyLineSize() + at1->getPolyLineSize(); Chris@16: (at1->getOtherActiveTail())->setPolyLineSize(accumulate); Chris@16: (at2->getOtherActiveTail())->setPolyLineSize(accumulate); Chris@16: Chris@16: at1->getOtherActiveTail()->copyHoles(*at1); Chris@16: at1->getOtherActiveTail()->copyHoles(*at2); Chris@16: destroyActiveTail(at1); Chris@16: destroyActiveTail(at2); Chris@16: return 0; Chris@16: } Chris@16: Chris@16: //solid indicates if it was joined by a solit or a space Chris@16: template Chris@16: template Chris@16: inline ActiveTail* ActiveTail::joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, Chris@16: std::vector& outBufferTmp) { Chris@16: //checks to see if we closed a figure Chris@16: if(at1->isOtherTail(*at2)){ Chris@16: //value of solid tells us if we closed solid or hole Chris@16: //and output the solid or handle the hole appropriately Chris@16: //if the hole needs to fracture across horizontal partition boundary we need to notify Chris@16: //the calling context to do so Chris@16: if(solid) { Chris@16: //the chains are being joined because there is solid to the right Chris@16: //this means that if the figure is closed at this point it must be a hole Chris@16: //because otherwise it would have to have another vertex to the right of this one Chris@16: //and would not be closed at this point Chris@16: return at1; Chris@16: } else { Chris@16: //assert pG != 0 Chris@16: //the figure that was closed is a shell Chris@16: outBufferTmp.push_back(at1); Chris@16: at1->copyHoles(*at2); //there should not be holes on at2, but if there are, copy them over Chris@16: } Chris@16: return 0; Chris@16: } Chris@16: //join the two partial polygons into one large partial polygon Chris@16: at1->getTail()->joinTailToTail(*(at2->getTail())); Chris@16: *(at1->getOtherActiveTail()) = ActiveTail(at1->getOtherTail(), at2->getOtherActiveTail()); Chris@16: *(at2->getOtherActiveTail()) = ActiveTail(at2->getOtherTail(), at1->getOtherActiveTail()); Chris@16: Chris@16: int accumulate = at2->getPolyLineSize() + at1->getPolyLineSize(); Chris@16: (at1->getOtherActiveTail())->setPolyLineSize(accumulate); Chris@16: (at2->getOtherActiveTail())->setPolyLineSize(accumulate); Chris@16: Chris@16: at1->getOtherActiveTail()->copyHoles(*at1); Chris@16: at1->getOtherActiveTail()->copyHoles(*at2); Chris@16: destroyActiveTail(at1); Chris@16: destroyActiveTail(at2); Chris@16: return 0; Chris@16: } Chris@16: Chris@16: template inline typename std::map::iterator findAtNext(std::map& theMap, Chris@16: typename std::map::iterator pos, const TKey& key) Chris@16: { Chris@16: if(pos == theMap.end()) return theMap.find(key); Chris@16: //if they match the mapItr is pointing to the correct position Chris@16: if(pos->first < key) { Chris@16: return theMap.find(key); Chris@16: } Chris@16: if(pos->first > key) { Chris@16: return theMap.end(); Chris@16: } Chris@16: //else they are equal and no need to do anything to the iterator Chris@16: return pos; Chris@16: } Chris@16: Chris@16: // createActiveTailsAsPair is called in these two end cases of geometry Chris@16: // 1. lower left concave corner Chris@16: // ###| Chris@16: // ###| Chris@16: // ###|### Chris@16: // ###|### Chris@16: // 2. lower left convex corner Chris@16: // |### Chris@16: // |### Chris@16: // | Chris@16: // | Chris@16: // In case 1 there may be a hole propigated up from the bottom. If the fracture option is enabled Chris@16: // the two active tails that form the filament fracture line edges can become the new active tail pair Chris@16: // by pushing x and y onto them. Otherwise the hole simply needs to be associated to one of the new active tails Chris@16: // with add hole Chris@16: template Chris@16: inline std::pair*, ActiveTail*> createActiveTailsAsPair(Unit x, Unit y, bool solid, ActiveTail* phole, bool fractureHoles) { Chris@16: ActiveTail* at1 = 0; Chris@16: ActiveTail* at2 = 0; Chris@16: if(!phole || !fractureHoles){ Chris@16: at1 = createActiveTail(); Chris@16: at2 = createActiveTail(); Chris@16: (*at1) = ActiveTail(VERTICAL, x, solid, at2); Chris@16: (*at2) = ActiveTail(HORIZONTAL, y, !solid, at1); Chris@16: //provide a function through activeTail class to provide this Chris@16: at1->getTail()->joinHeadToHead(*(at2->getTail())); Chris@16: Chris@16: at1->addPolyLineSize(1); Chris@16: at2->addPolyLineSize(1); Chris@16: Chris@16: if(phole) Chris@16: at1->addHole(phole, fractureHoles); //assert fractureHoles == false Chris@16: return std::pair*, ActiveTail*>(at1, at2); Chris@16: } Chris@16: //assert phole is not null Chris@16: //assert fractureHoles is true Chris@16: if(phole->getOrient() == VERTICAL) { Chris@16: at2 = phole; Chris@16: } else { Chris@16: at2 = phole->getOtherActiveTail(); //should never be executed since orientation is expected to be vertical Chris@16: } Chris@16: //assert solid == false, we should be creating a corner with solid below and to the left if there was a hole Chris@16: at1 = at2->getOtherActiveTail(); Chris@16: //assert at1 is horizontal Chris@16: at1->pushCoordinate(x); Chris@16: //assert at2 is vertical Chris@16: at2->pushCoordinate(y); Chris@16: Chris@16: return std::pair*, ActiveTail*>(at1, at2); Chris@16: } Chris@16: Chris@16: /* Chris@16: * | Chris@16: * | Chris@16: * = Chris@16: * |######## Chris@16: * |######## (add a new ActiveTail in the tailMap_). Chris@16: * |######## Chris@16: * |######## Chris@16: * |######## Chris@16: * = Chris@16: * | Chris@16: * | Chris@16: * Chris@16: * NOTE: Call this only if you are sure that the $ledege$ is not in the tailMap_ Chris@16: */ Chris@16: template Chris@16: inline void ScanLineToPolygonItrs:: Chris@16: insertNewLeftEdgeIntoTailMap(Unit currentX, Unit yBegin, Unit yEnd, Chris@16: typename std::map *>::iterator &hint){ Chris@16: ActiveTail *currentTail = NULL; Chris@16: std::pair*, ActiveTail*> tailPair = Chris@16: createActiveTailsAsPair(currentX, yBegin, true, currentTail, Chris@16: fractureHoles_); Chris@16: currentTail = tailPair.first; Chris@16: if(!tailMap_.empty()){ Chris@16: ++hint; Chris@16: } Chris@16: hint = tailMap_.insert(hint, std::make_pair(yBegin, tailPair.second)); Chris@16: currentTail->pushCoordinate(yEnd); ++hint; Chris@16: hint = tailMap_.insert(hint, std::make_pair(yEnd, currentTail)); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void ScanLineToPolygonItrs:: Chris@16: closePartialSimplePolygon(Unit currentX, ActiveTail*pfig, Chris@16: ActiveTail*ppfig){ Chris@16: pfig->pushCoordinate(currentX); Chris@16: ActiveTail::joinChains(pfig, ppfig, false, outputPolygons_); Chris@16: } Chris@16: /* Chris@16: * If the invariant is maintained correctly then left edges can do the Chris@16: * following. Chris@16: * Chris@16: * =### Chris@16: * ####### Chris@16: * ####### Chris@16: * ####### Chris@16: * ####### Chris@16: * =### Chris@16: * |### (input left edge) Chris@16: * |### Chris@16: * =### Chris@16: * ####### Chris@16: * ####### Chris@16: * =### Chris@16: */ Chris@16: template Chris@16: inline void ScanLineToPolygonItrs:: Chris@16: updatePartialSimplePolygonsWithLeftEdges(Unit currentX, Chris@16: const std::vector > &leftEdges, size_t vertexThreshold){ Chris@16: typename std::map* >::iterator succ, succ1; Chris@16: typename std::map* >::iterator pred, pred1, hint; Chris@16: Unit begin, end; Chris@16: ActiveTail *pfig, *ppfig; Chris@16: std::pair*, ActiveTail*> tailPair; Chris@16: size_t pfig_size = 0; Chris@16: Chris@16: hint = tailMap_.begin(); Chris@16: for(size_t i=0; i < leftEdges.size(); i++){ Chris@16: begin = leftEdges[i].get(LOW); end = leftEdges[i].get(HIGH); Chris@16: succ = findAtNext(tailMap_, hint, begin); Chris@16: pred = findAtNext(tailMap_, hint, end); Chris@16: Chris@16: if(succ != tailMap_.end() && pred != tailMap_.end()){ //CASE-1// Chris@16: //join the corresponding active tails// Chris@16: pfig = succ->second; ppfig = pred->second; Chris@16: pfig_size = pfig->getPolyLineSize() + ppfig->getPolyLineSize(); Chris@16: Chris@16: if(pfig_size >= vertexThreshold){ Chris@16: size_t bsize = pfig->getPolyLineSize(); Chris@16: size_t usize = ppfig->getPolyLineSize(); Chris@16: Chris@16: if(usize+2 < vertexThreshold){ Chris@16: //cut-off the lower piece (succ1, succ) join (succ1, pred)// Chris@16: succ1 = succ; --succ1; Chris@16: assert((succ1 != tailMap_.end()) && Chris@16: ((succ->second)->getOtherActiveTail() == succ1->second)); Chris@16: closePartialSimplePolygon(currentX, succ1->second, succ->second); Chris@16: tailPair = createActiveTailsAsPair(currentX, succ1->first, Chris@16: true, NULL, fractureHoles_); Chris@16: Chris@16: //just update the succ1 with new ActiveTail*// Chris@16: succ1->second = tailPair.second; Chris@16: ActiveTail::joinChains(tailPair.first, pred->second, true, Chris@16: outputPolygons_); Chris@16: }else if(bsize+2 < vertexThreshold){ Chris@16: //cut-off the upper piece () join ()// Chris@16: pred1 = pred; ++pred1; Chris@16: assert(pred1 != tailMap_.end() && Chris@16: ((pred1->second)->getOtherActiveTail() == pred->second)); Chris@16: closePartialSimplePolygon(currentX, pred->second, pred1->second); Chris@16: Chris@16: //just update the pred1 with ActiveTail* = pfig// Chris@16: pred1->second = pfig; Chris@16: pfig->pushCoordinate(currentX); Chris@16: pfig->pushCoordinate(pred1->first); Chris@16: }else{ Chris@16: //cut both and create an left edge between (pred->first, succ1)// Chris@16: succ1 = succ; --succ1; Chris@16: pred1 = pred; ++pred1; Chris@16: assert(pred1 != tailMap_.end() && succ1 != tailMap_.end()); Chris@16: assert((pred1->second)->getOtherActiveTail() == pred->second); Chris@16: assert((succ1->second)->getOtherActiveTail() == succ->second); Chris@16: Chris@16: closePartialSimplePolygon(currentX, succ1->second, succ->second); Chris@16: closePartialSimplePolygon(currentX, pred->second, pred1->second); Chris@16: Chris@16: tailPair = createActiveTailsAsPair(currentX, succ1->first, Chris@16: true, NULL, fractureHoles_); Chris@16: succ1->second = tailPair.second; Chris@16: pred1->second = tailPair.first; Chris@16: (tailPair.first)->pushCoordinate(pred1->first); Chris@16: } Chris@16: }else{ Chris@16: //just join them with closing// Chris@16: pfig->pushCoordinate(currentX); Chris@16: ActiveTail::joinChains(pfig, ppfig, true, outputPolygons_); Chris@16: } Chris@16: hint = pred; ++hint; Chris@16: tailMap_.erase(succ); tailMap_.erase(pred); Chris@16: }else if(succ == tailMap_.end() && pred != tailMap_.end()){ //CASE-2// Chris@16: //succ is missing in the map, first insert it into the map// Chris@16: tailPair = createActiveTailsAsPair(currentX, begin, true, NULL, Chris@16: fractureHoles_); Chris@16: hint = pred; ++hint; Chris@16: hint = tailMap_.insert(hint, std::make_pair(begin, tailPair.second)); Chris@16: Chris@16: pfig = pred->second; Chris@16: pfig_size = pfig->getPolyLineSize() + 2; Chris@16: if(pfig_size >= vertexThreshold){ Chris@16: //cut-off piece from [pred, pred1] , add [begin, pred1]// Chris@16: pred1 = pred; ++pred1; Chris@16: assert((pred1 != tailMap_.end()) && Chris@16: ((pred1->second)->getOtherActiveTail() == pred->second)); Chris@16: closePartialSimplePolygon(currentX, pred->second, pred1->second); Chris@16: Chris@16: //update: we need left edge between (begin, pred1->first)// Chris@16: pred1->second = tailPair.first; Chris@16: (tailPair.first)->pushCoordinate(pred1->first); Chris@16: }else{ Chris@16: //just join// Chris@16: ActiveTail::joinChains(tailPair.first, pfig, Chris@16: true, outputPolygons_); Chris@16: } Chris@16: tailMap_.erase(pred); Chris@16: }else if(succ != tailMap_.end() && pred == tailMap_.end()){ //CASE-3// Chris@16: //pred is missing in the map, first insert it into the map// Chris@16: hint = succ; ++hint; Chris@16: hint = tailMap_.insert(hint, std::make_pair(end, (ActiveTail *) NULL)); Chris@16: pfig = succ->second; Chris@16: pfig_size = pfig->getPolyLineSize() + 2; Chris@16: if(pfig_size >= vertexThreshold){ Chris@16: //this figure needs cutting here// Chris@16: succ1 = succ; --succ1; Chris@16: assert((succ1 != tailMap_.end()) && Chris@16: (succ1->second == pfig->getOtherActiveTail())); Chris@16: ppfig = succ1->second; Chris@16: closePartialSimplePolygon(currentX, ppfig, pfig); Chris@16: Chris@16: //update: we need a left edge between (succ1->first, end)// Chris@16: tailPair = createActiveTailsAsPair(currentX, succ1->first, Chris@16: true, NULL, fractureHoles_); Chris@16: succ1->second = tailPair.second; Chris@16: hint->second = tailPair.first; Chris@16: (tailPair.first)->pushCoordinate(end); Chris@16: }else{ Chris@16: //no cutting needed// Chris@16: hint->second = pfig; Chris@16: pfig->pushCoordinate(currentX); Chris@16: pfig->pushCoordinate(end); Chris@16: } Chris@16: tailMap_.erase(succ); Chris@16: }else{ Chris@16: //insert both pred and succ// Chris@16: insertNewLeftEdgeIntoTailMap(currentX, begin, end, hint); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline void ScanLineToPolygonItrs:: Chris@16: updatePartialSimplePolygonsWithRightEdges(Unit currentX, Chris@16: const std::vector > &rightEdges, size_t vertexThreshold) Chris@16: { Chris@16: Chris@16: typename std::map* >::iterator succ, pred, hint; Chris@16: std::pair*, ActiveTail*> tailPair; Chris@16: Unit begin, end; Chris@16: size_t i = 0; Chris@16: //If rightEdges is non-empty Then tailMap_ is non-empty // Chris@16: assert(rightEdges.empty() || !tailMap_.empty() ); Chris@16: Chris@16: while( i < rightEdges.size() ){ Chris@16: //find the interval in the tailMap which contains this interval// Chris@16: pred = tailMap_.lower_bound(rightEdges[i].get(HIGH)); Chris@16: assert(pred != tailMap_.end()); Chris@16: succ = pred; --succ; Chris@16: assert(pred != succ); Chris@16: end = pred->first; begin = succ->first; Chris@16: Chris@16: //we now have a [begin, end] // Chris@16: bool found_solid_opening = false; Chris@16: bool erase_succ = true, erase_pred = true; Chris@16: Unit solid_opening_begin = 0; Chris@16: Unit solid_opening_end = 0; Chris@16: size_t j = i+1; Chris@16: ActiveTail *pfig = succ->second; Chris@16: ActiveTail *ppfig = pred->second; Chris@16: size_t partial_fig_size = pfig->getPolyLineSize(); Chris@16: //Invariant:// Chris@16: assert(succ->second && (pfig)->getOtherActiveTail() == ppfig); Chris@16: Chris@16: hint = succ; Chris@16: Unit key = rightEdges[i].get(LOW); Chris@16: if(begin != key){ Chris@16: found_solid_opening = true; Chris@16: solid_opening_begin = begin; solid_opening_end = key; Chris@16: } Chris@16: Chris@16: while(j < rightEdges.size() && rightEdges[j].get(HIGH) <= end){ Chris@16: if(rightEdges[j-1].get(HIGH) != rightEdges[j].get(LOW)){ Chris@16: if(!found_solid_opening){ Chris@16: found_solid_opening = true; Chris@16: solid_opening_begin = rightEdges[j-1].get(HIGH); Chris@16: solid_opening_end = rightEdges[j].get(LOW); Chris@16: }else{ Chris@16: ++hint; Chris@16: insertNewLeftEdgeIntoTailMap(currentX, Chris@16: rightEdges[j-1].get(HIGH), rightEdges[j].get(LOW), hint); Chris@16: } Chris@16: } Chris@16: j++; Chris@16: } Chris@16: Chris@16: //trailing edge// Chris@16: if(end != rightEdges[j-1].get(HIGH)){ Chris@16: if(!found_solid_opening){ Chris@16: found_solid_opening = true; Chris@16: solid_opening_begin = rightEdges[j-1].get(HIGH); solid_opening_end = end; Chris@16: }else{ Chris@16: // a solid opening has been found already, we need to insert a new left Chris@16: // between [rightEdges[j-1].get(HIGH), end] Chris@16: Unit lbegin = rightEdges[j-1].get(HIGH); Chris@16: tailPair = createActiveTailsAsPair(currentX, lbegin, true, NULL, Chris@16: fractureHoles_); Chris@16: hint = tailMap_.insert(pred, std::make_pair(lbegin, tailPair.second)); Chris@16: pred->second = tailPair.first; Chris@16: (tailPair.first)->pushCoordinate(end); Chris@16: erase_pred = false; Chris@16: } Chris@16: } Chris@16: Chris@16: size_t vertex_delta = ((begin != solid_opening_begin) && Chris@16: (end != solid_opening_end)) ? 4 : 2; Chris@16: Chris@16: if(!found_solid_opening){ Chris@16: //just close the figure, TODO: call closePartialPolygon// Chris@16: pfig->pushCoordinate(currentX); Chris@16: ActiveTail::joinChains(pfig, ppfig, false, outputPolygons_); Chris@16: hint = pred; ++hint; Chris@16: }else if(partial_fig_size+vertex_delta >= vertexThreshold){ Chris@16: //close the figure and add a pseudo left-edge// Chris@16: closePartialSimplePolygon(currentX, pfig, ppfig); Chris@16: assert(begin != solid_opening_begin || end != solid_opening_end); Chris@16: Chris@16: if(begin != solid_opening_begin && end != solid_opening_end){ Chris@16: insertNewLeftEdgeIntoTailMap(currentX, solid_opening_begin, Chris@16: solid_opening_end, hint); Chris@16: }else if(begin == solid_opening_begin){ Chris@16: //we just need to update the succ in the tailMap_// Chris@16: tailPair = createActiveTailsAsPair(currentX, solid_opening_begin, Chris@16: true, NULL, fractureHoles_); Chris@16: succ->second = tailPair.second; Chris@16: hint = succ; ++hint; Chris@16: hint = tailMap_.insert(pred, std::make_pair(solid_opening_end, Chris@16: tailPair.first)); Chris@16: (tailPair.first)->pushCoordinate(solid_opening_end); Chris@16: erase_succ = false; Chris@16: }else{ Chris@16: //we just need to update the pred in the tailMap_// Chris@16: tailPair = createActiveTailsAsPair(currentX, solid_opening_begin, Chris@16: true, NULL, fractureHoles_); Chris@16: hint = tailMap_.insert(pred, std::make_pair(solid_opening_begin, Chris@16: tailPair.second)); Chris@16: pred->second = tailPair.first; Chris@16: (tailPair.first)->pushCoordinate(solid_opening_end); Chris@16: erase_pred = false; Chris@16: } Chris@16: }else{ Chris@16: //continue the figure (by adding at-most two new vertices)// Chris@16: if(begin != solid_opening_begin){ Chris@16: pfig->pushCoordinate(currentX); Chris@16: pfig->pushCoordinate(solid_opening_begin); Chris@16: //insert solid_opening_begin// Chris@16: hint = succ; ++hint; Chris@16: hint = tailMap_.insert(hint, std::make_pair(solid_opening_begin, pfig)); Chris@16: }else{ Chris@16: erase_succ = false; Chris@16: } Chris@16: Chris@16: if(end != solid_opening_end){ Chris@16: std::pair*, ActiveTail*> tailPair = Chris@16: createActiveTailsAsPair(currentX, solid_opening_end, false, Chris@16: NULL, fractureHoles_); Chris@16: hint = pred; ++hint; Chris@16: hint = tailMap_.insert(hint, std::make_pair(solid_opening_end, Chris@16: tailPair.second)); Chris@16: ActiveTail::joinChains(tailPair.first, ppfig, false, Chris@16: outputPolygons_); Chris@16: }else{ Chris@16: erase_pred = false; Chris@16: } Chris@16: } Chris@16: Chris@16: //Remove the pred and succ if necessary// Chris@16: if(erase_succ){ Chris@16: tailMap_.erase(succ); Chris@16: } Chris@16: if(erase_pred){ Chris@16: tailMap_.erase(pred); Chris@16: } Chris@16: i = j; Chris@16: } Chris@16: } Chris@16: Chris@16: // Maintains the following invariant: Chris@16: // a. All the partial polygons formed at any state can be closed Chris@16: // by a single edge. Chris@16: template Chris@16: inline void ScanLineToPolygonItrs:: Chris@16: maintainPartialSimplePolygonInvariant(iterator& beginOutput, Chris@16: iterator& endOutput, Unit currentX, const std::vector >& l, Chris@16: const std::vector >& r, size_t vertexThreshold) { Chris@16: Chris@16: clearOutput_(); Chris@16: if(!l.empty()){ Chris@16: updatePartialSimplePolygonsWithLeftEdges(currentX, l, vertexThreshold); Chris@16: } Chris@16: Chris@16: if(!r.empty()){ Chris@16: updatePartialSimplePolygonsWithRightEdges(currentX, r, vertexThreshold); Chris@16: } Chris@16: beginOutput = outputPolygons_.begin(); Chris@16: endOutput = outputPolygons_.end(); Chris@16: Chris@16: } Chris@16: Chris@16: //Process edges connects vertical input edges (right or left edges of figures) to horizontal edges stored as member Chris@16: //data of the scanline object. It also creates now horizontal edges as needed to construct figures from edge data. Chris@16: // Chris@16: //There are only 12 geometric end cases where the scanline intersects a horizontal edge and even fewer unique Chris@16: //actions to take: Chris@16: // 1. Solid on both sides of the vertical partition after the current position and space on both sides before Chris@16: // ###|### Chris@16: // ###|### Chris@16: // | Chris@16: // | Chris@16: // This case does not need to be handled because there is no vertical edge at the current x coordinate. Chris@16: // Chris@16: // 2. Solid on both sides of the vertical partition before the current position and space on both sides after Chris@16: // | Chris@16: // | Chris@16: // ###|### Chris@16: // ###|### Chris@16: // This case does not need to be handled because there is no vertical edge at the current x coordinate. Chris@16: // Chris@16: // 3. Solid on the left of the vertical partition after the current position and space elsewhere Chris@16: // ###| Chris@16: // ###| Chris@16: // | Chris@16: // | Chris@16: // The horizontal edge from the left is found and turns upward because of the vertical right edge to become Chris@16: // the currently active vertical edge. Chris@16: // Chris@16: // 4. Solid on the left of the vertical partion before the current position and space elsewhere Chris@16: // | Chris@16: // | Chris@16: // ###| Chris@16: // ###| Chris@16: // The horizontal edge from the left is found and joined to the currently active vertical edge. Chris@16: // Chris@16: // 5. Solid to the right above and below and solid to the left above current position. Chris@16: // ###|### Chris@16: // ###|### Chris@16: // |### Chris@16: // |### Chris@16: // The horizontal edge from the left is found and joined to the currently active vertical edge, Chris@16: // potentially closing a hole. Chris@16: // Chris@16: // 6. Solid on the left of the vertical partion before the current position and solid to the right above and below Chris@16: // |### Chris@16: // |### Chris@16: // ###|### Chris@16: // ###|### Chris@16: // The horizontal edge from the left is found and turns upward because of the vertical right edge to become Chris@16: // the currently active vertical edge. Chris@16: // Chris@16: // 7. Solid on the right of the vertical partition after the current position and space elsewhere Chris@16: // |### Chris@16: // |### Chris@16: // | Chris@16: // | Chris@16: // Create two new ActiveTails, one is added to the horizontal edges and the other becomes the vertical currentTail Chris@16: // Chris@16: // 8. Solid on the right of the vertical partion before the current position and space elsewhere Chris@16: // | Chris@16: // | Chris@16: // |### Chris@16: // |### Chris@16: // The currentTail vertical edge turns right and is added to the horizontal edges data Chris@16: // Chris@16: // 9. Solid to the right above and solid to the left above and below current position. Chris@16: // ###|### Chris@16: // ###|### Chris@16: // ###| Chris@16: // ###| Chris@16: // The currentTail vertical edge turns right and is added to the horizontal edges data Chris@16: // Chris@16: // 10. Solid on the left of the vertical partion above and below the current position and solid to the right below Chris@16: // ###| Chris@16: // ###| Chris@16: // ###|### Chris@16: // ###|### Chris@16: // Create two new ActiveTails, one is added to the horizontal edges data and the other becomes the vertical currentTail Chris@16: // Chris@16: // 11. Solid to the right above and solid to the left below current position. Chris@16: // |### Chris@16: // |### Chris@16: // ###| Chris@16: // ###| Chris@16: // The currentTail vertical edge joins the horizontal edge from the left (may close a polygon) Chris@16: // Create two new ActiveTails, one is added to the horizontal edges data and the other becomes the vertical currentTail Chris@16: // Chris@16: // 12. Solid on the left of the vertical partion above the current position and solid to the right below Chris@16: // ###| Chris@16: // ###| Chris@16: // |### Chris@16: // |### Chris@16: // The currentTail vertical edge turns right and is added to the horizontal edges data. Chris@16: // The horizontal edge from the left turns upward and becomes the currentTail vertical edge Chris@16: // Chris@16: template Chris@16: inline void ScanLineToPolygonItrs:: Chris@16: processEdges(iterator& beginOutput, iterator& endOutput, Chris@16: Unit currentX, std::vector >& leftEdges, Chris@16: std::vector >& rightEdges, Chris@16: size_t vertexThreshold) { Chris@16: clearOutput_(); Chris@16: typename std::map*>::iterator nextMapItr; Chris@16: //foreach edge Chris@16: unsigned int leftIndex = 0; Chris@16: unsigned int rightIndex = 0; Chris@16: bool bottomAlreadyProcessed = false; Chris@16: ActiveTail* currentTail = 0; Chris@16: const Unit UnitMax = (std::numeric_limits::max)(); Chris@16: Chris@16: if(vertexThreshold < (std::numeric_limits::max)()){ Chris@16: maintainPartialSimplePolygonInvariant(beginOutput, endOutput, currentX, Chris@16: leftEdges, rightEdges, vertexThreshold); Chris@16: return; Chris@16: } Chris@16: Chris@16: nextMapItr = tailMap_.begin(); Chris@16: while(leftIndex < leftEdges.size() || rightIndex < rightEdges.size()) { Chris@16: interval_data edges[2] = {interval_data (UnitMax, UnitMax), Chris@16: interval_data (UnitMax, UnitMax)}; Chris@16: bool haveNextEdge = true; Chris@16: if(leftIndex < leftEdges.size()) Chris@16: edges[0] = leftEdges[leftIndex]; Chris@16: else Chris@16: haveNextEdge = false; Chris@16: if(rightIndex < rightEdges.size()) Chris@16: edges[1] = rightEdges[rightIndex]; Chris@16: else Chris@16: haveNextEdge = false; Chris@16: bool trailingEdge = edges[1].get(LOW) < edges[0].get(LOW); Chris@16: interval_data & edge = edges[trailingEdge]; Chris@16: interval_data & nextEdge = edges[!trailingEdge]; Chris@16: //process this edge Chris@16: if(!bottomAlreadyProcessed) { Chris@16: //assert currentTail = 0 Chris@16: Chris@16: //process the bottom end of this edge Chris@16: typename std::map*>::iterator thisMapItr = findAtNext(tailMap_, nextMapItr, edge.get(LOW)); Chris@16: if(thisMapItr != tailMap_.end()) { Chris@16: //there is an edge in the map at the low end of this edge Chris@16: //it needs to turn upward and become the current tail Chris@16: ActiveTail* tail = thisMapItr->second; Chris@16: if(currentTail) { Chris@16: //stitch currentTail into this tail Chris@16: currentTail = tail->addHole(currentTail, fractureHoles_); Chris@16: if(!fractureHoles_) Chris@16: currentTail->pushCoordinate(currentX); Chris@16: } else { Chris@16: currentTail = tail; Chris@16: currentTail->pushCoordinate(currentX); Chris@16: } Chris@16: //assert currentTail->getOrient() == VERTICAL Chris@16: nextMapItr = thisMapItr; //set nextMapItr to the next position after this one Chris@16: ++nextMapItr; Chris@16: //remove thisMapItr from the map Chris@16: tailMap_.erase(thisMapItr); Chris@16: } else { Chris@16: //there is no edge in the map at the low end of this edge Chris@16: //we need to create one and another one to be the current vertical tail Chris@16: //if this is a trailing edge then there is space to the right of the vertical edge Chris@16: //so pass the inverse of trailingEdge to indicate solid to the right Chris@16: std::pair*, ActiveTail*> tailPair = Chris@16: createActiveTailsAsPair(currentX, edge.get(LOW), !trailingEdge, currentTail, fractureHoles_); Chris@16: currentTail = tailPair.first; Chris@16: tailMap_.insert(nextMapItr, std::pair*>(edge.get(LOW), tailPair.second)); Chris@16: // leave nextMapItr unchanged Chris@16: } Chris@16: Chris@16: } Chris@16: if(haveNextEdge && edge.get(HIGH) == nextEdge.get(LOW)) { Chris@16: //the top of this edge is equal to the bottom of the next edge, process them both Chris@16: bottomAlreadyProcessed = true; Chris@16: typename std::map*>::iterator thisMapItr = findAtNext(tailMap_, nextMapItr, edge.get(HIGH)); Chris@16: if(thisMapItr == tailMap_.end()) //assert this should never happen Chris@16: return; Chris@16: if(trailingEdge) { Chris@16: //geometry at this position Chris@16: // |## Chris@16: // |## Chris@16: // ----- Chris@16: // ##| Chris@16: // ##| Chris@16: //current tail should join thisMapItr tail Chris@16: ActiveTail* tail = thisMapItr->second; Chris@16: //pass false because they are being joined because space is to the right and it will close a solid figure Chris@16: ActiveTail::joinChains(currentTail, tail, false, outputPolygons_); Chris@16: //two new tails are created, the vertical becomes current tail, the horizontal becomes thisMapItr tail Chris@16: //pass true becuase they are created at the lower left corner of some solid Chris@16: //pass null because there is no hole pointer possible Chris@16: std::pair*, ActiveTail*> tailPair = Chris@16: createActiveTailsAsPair(currentX, edge.get(HIGH), true, 0, fractureHoles_); Chris@16: currentTail = tailPair.first; Chris@16: thisMapItr->second = tailPair.second; Chris@16: } else { Chris@16: //geometry at this position Chris@16: // ##| Chris@16: // ##| Chris@16: // ----- Chris@16: // |## Chris@16: // |## Chris@16: //current tail should turn right Chris@16: currentTail->pushCoordinate(edge.get(HIGH)); Chris@16: //thisMapItr tail should turn up Chris@16: thisMapItr->second->pushCoordinate(currentX); Chris@16: //thisMapItr tail becomes current tail and current tail becomes thisMapItr tail Chris@16: std::swap(currentTail, thisMapItr->second); Chris@16: } Chris@16: nextMapItr = thisMapItr; //set nextMapItr to the next position after this one Chris@16: ++nextMapItr; Chris@16: } else { Chris@16: //there is a gap between the top of this edge and the bottom of the next, process the top of this edge Chris@16: bottomAlreadyProcessed = false; Chris@16: //process the top of this edge Chris@16: typename std::map*>::iterator thisMapItr = findAtNext(tailMap_, nextMapItr, edge.get(HIGH)); Chris@16: if(thisMapItr != tailMap_.end()) { Chris@16: //thisMapItr is pointing to a horizontal edge in the map at the top of this vertical edge Chris@16: //we need to join them and potentially close a figure Chris@16: //assert currentTail != 0 Chris@16: ActiveTail* tail = thisMapItr->second; Chris@16: //pass the opositve of trailing edge to mean that they are joined because of solid to the right Chris@16: currentTail = ActiveTail::joinChains(currentTail, tail, !trailingEdge, outputPolygons_); Chris@16: nextMapItr = thisMapItr; //set nextMapItr to the next position after this one Chris@16: ++nextMapItr; Chris@16: if(currentTail) { //figure is not closed// Chris@16: Unit nextItrY = UnitMax; Chris@16: if(nextMapItr != tailMap_.end()) { Chris@16: nextItrY = nextMapItr->first; Chris@16: } Chris@16: //for it to be a hole this must have been a left edge Chris@16: Unit leftY = UnitMax; Chris@16: if(leftIndex + 1 < leftEdges.size()) Chris@16: leftY = leftEdges[leftIndex+1].get(LOW); Chris@16: Unit rightY = nextEdge.get(LOW); Chris@16: if(!haveNextEdge || (nextItrY < leftY && nextItrY < rightY)) { Chris@16: //we need to add it to the next edge above it in the map Chris@16: tail = nextMapItr->second; Chris@16: tail = tail->addHole(currentTail, fractureHoles_); Chris@16: if(fractureHoles_) { Chris@16: //some small additional work stitching in the filament Chris@16: tail->pushCoordinate(nextItrY); Chris@16: nextMapItr->second = tail; Chris@16: } Chris@16: //set current tail to null Chris@16: currentTail = 0; Chris@16: } Chris@16: } Chris@16: //delete thisMapItr from the map Chris@16: tailMap_.erase(thisMapItr); Chris@16: } else { Chris@16: //currentTail must turn right and be added into the map Chris@16: currentTail->pushCoordinate(edge.get(HIGH)); Chris@16: //assert currentTail->getOrient() == HORIZONTAL Chris@16: tailMap_.insert(nextMapItr, std::pair*>(edge.get(HIGH), currentTail)); Chris@16: //set currentTail to null Chris@16: currentTail = 0; Chris@16: //leave nextMapItr unchanged, it is still next Chris@16: } Chris@16: } Chris@16: Chris@16: //increment index Chris@16: leftIndex += !trailingEdge; Chris@16: rightIndex += trailingEdge; Chris@16: } //end while Chris@16: beginOutput = outputPolygons_.begin(); Chris@16: endOutput = outputPolygons_.end(); Chris@16: } //end function Chris@16: Chris@16: template Chris@16: inline void ScanLineToPolygonItrs::clearOutput_() { Chris@16: for(std::size_t i = 0; i < outputPolygons_.size(); ++i) { Chris@16: ActiveTail* at1 = outputPolygons_[i].yield(); Chris@16: const std::list*>& holes = at1->getHoles(); Chris@16: for(typename std::list*>::const_iterator litr = holes.begin(); litr != holes.end(); ++litr) { Chris@16: //delete the hole Chris@16: (*litr)->destroyContents(); Chris@16: destroyActiveTail((*litr)->getOtherActiveTail()); Chris@16: destroyActiveTail((*litr)); Chris@16: } Chris@16: //delete the polygon Chris@16: at1->destroyContents(); Chris@16: //at2 contents are the same as at1, so it should not destroy them Chris@16: destroyActiveTail((at1)->getOtherActiveTail()); Chris@16: destroyActiveTail(at1); Chris@16: } Chris@16: outputPolygons_.clear(); Chris@16: } Chris@16: Chris@16: } //polygon_formation namespace Chris@16: Chris@16: template Chris@16: struct geometry_concept > { Chris@16: typedef polygon_90_with_holes_concept type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct geometry_concept > { Chris@16: typedef polygon_90_concept type; Chris@16: }; Chris@16: Chris@16: //public API to access polygon formation algorithm Chris@16: template Chris@16: unsigned int get_polygons(output_container& container, Chris@16: iterator_type begin, iterator_type end, orientation_2d orient, Chris@16: bool fracture_holes, concept_type, Chris@16: size_t sliceThreshold = (std::numeric_limits::max)() ) { Chris@16: typedef typename output_container::value_type polygon_type; Chris@16: typedef typename std::iterator_traits::value_type::first_type coordinate_type; Chris@16: polygon_type poly; Chris@16: unsigned int countPolygons = 0; Chris@16: typedef typename geometry_concept::type polygon_concept_type; Chris@16: polygon_formation::ScanLineToPolygonItrs scanlineToPolygonItrsV(fracture_holes); Chris@16: polygon_formation::ScanLineToPolygonItrs scanlineToPolygonItrsH(fracture_holes); Chris@16: std::vector > leftEdges; Chris@16: std::vector > rightEdges; Chris@16: coordinate_type prevPos = (std::numeric_limits::max)(); Chris@16: coordinate_type prevY = (std::numeric_limits::max)(); Chris@16: int count = 0; Chris@16: for(iterator_type itr = begin; Chris@16: itr != end; ++ itr) { Chris@16: coordinate_type pos = (*itr).first; Chris@16: if(pos != prevPos) { Chris@16: if(orient == VERTICAL) { Chris@16: typename polygon_formation::ScanLineToPolygonItrs::iterator itrPoly, itrPolyEnd; Chris@16: scanlineToPolygonItrsV.processEdges(itrPoly, itrPolyEnd, prevPos, Chris@16: leftEdges, rightEdges, sliceThreshold); Chris@16: for( ; itrPoly != itrPolyEnd; ++ itrPoly) { Chris@16: ++countPolygons; Chris@16: assign(poly, *itrPoly); Chris@16: container.insert(container.end(), poly); Chris@16: } Chris@16: } else { Chris@16: typename polygon_formation::ScanLineToPolygonItrs::iterator itrPoly, itrPolyEnd; Chris@16: scanlineToPolygonItrsH.processEdges(itrPoly, itrPolyEnd, prevPos, Chris@16: leftEdges, rightEdges, sliceThreshold); Chris@16: for( ; itrPoly != itrPolyEnd; ++ itrPoly) { Chris@16: ++countPolygons; Chris@16: assign(poly, *itrPoly); Chris@16: container.insert(container.end(), poly); Chris@16: } Chris@16: } Chris@16: leftEdges.clear(); Chris@16: rightEdges.clear(); Chris@16: prevPos = pos; Chris@16: prevY = (*itr).second.first; Chris@16: count = (*itr).second.second; Chris@16: continue; Chris@16: } Chris@16: coordinate_type y = (*itr).second.first; Chris@16: if(count != 0 && y != prevY) { Chris@16: std::pair, int> element(interval_data(prevY, y), count); Chris@16: if(element.second == 1) { Chris@16: if(leftEdges.size() && leftEdges.back().high() == element.first.low()) { Chris@16: encompass(leftEdges.back(), element.first); Chris@16: } else { Chris@16: leftEdges.push_back(element.first); Chris@16: } Chris@16: } else { Chris@16: if(rightEdges.size() && rightEdges.back().high() == element.first.low()) { Chris@16: encompass(rightEdges.back(), element.first); Chris@16: } else { Chris@16: rightEdges.push_back(element.first); Chris@16: } Chris@16: } Chris@16: Chris@16: } Chris@16: prevY = y; Chris@16: count += (*itr).second.second; Chris@16: } Chris@16: if(orient == VERTICAL) { Chris@16: typename polygon_formation::ScanLineToPolygonItrs::iterator itrPoly, itrPolyEnd; Chris@16: scanlineToPolygonItrsV.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges, sliceThreshold); Chris@16: for( ; itrPoly != itrPolyEnd; ++ itrPoly) { Chris@16: ++countPolygons; Chris@16: assign(poly, *itrPoly); Chris@16: container.insert(container.end(), poly); Chris@16: } Chris@16: } else { Chris@16: typename polygon_formation::ScanLineToPolygonItrs::iterator itrPoly, itrPolyEnd; Chris@16: scanlineToPolygonItrsH.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges, sliceThreshold); Chris@16: Chris@16: for( ; itrPoly != itrPolyEnd; ++ itrPoly) { Chris@16: ++countPolygons; Chris@16: assign(poly, *itrPoly); Chris@16: container.insert(container.end(), poly); Chris@16: } Chris@16: } Chris@16: return countPolygons; Chris@16: } Chris@16: Chris@16: } Chris@16: } Chris@16: #endif