1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2008 by Sun Microsystems, Inc. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * $RCSfile: b2dmultirange.cxx,v $ 10*cdf0e10cSrcweir * $Revision: 1.8 $ 11*cdf0e10cSrcweir * 12*cdf0e10cSrcweir * This file is part of OpenOffice.org. 13*cdf0e10cSrcweir * 14*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 15*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 16*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 17*cdf0e10cSrcweir * 18*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 19*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 20*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 22*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 23*cdf0e10cSrcweir * 24*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 25*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 26*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 27*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 28*cdf0e10cSrcweir * 29*cdf0e10cSrcweir ************************************************************************/ 30*cdf0e10cSrcweir 31*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 32*cdf0e10cSrcweir #include "precompiled_basegfx.hxx" 33*cdf0e10cSrcweir 34*cdf0e10cSrcweir #include <rtl/math.hxx> 35*cdf0e10cSrcweir 36*cdf0e10cSrcweir #include <basegfx/tuple/b2dtuple.hxx> 37*cdf0e10cSrcweir #include <basegfx/range/b2drange.hxx> 38*cdf0e10cSrcweir #include <basegfx/range/b2dpolyrange.hxx> 39*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygon.hxx> 40*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx> 41*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx> 42*cdf0e10cSrcweir 43*cdf0e10cSrcweir #include <o3tl/vector_pool.hxx> 44*cdf0e10cSrcweir #include <boost/bind.hpp> 45*cdf0e10cSrcweir #include <boost/utility.hpp> 46*cdf0e10cSrcweir 47*cdf0e10cSrcweir #include <algorithm> 48*cdf0e10cSrcweir #include <deque> 49*cdf0e10cSrcweir #include <list> 50*cdf0e10cSrcweir 51*cdf0e10cSrcweir 52*cdf0e10cSrcweir namespace basegfx 53*cdf0e10cSrcweir { 54*cdf0e10cSrcweir namespace 55*cdf0e10cSrcweir { 56*cdf0e10cSrcweir // Generating a poly-polygon from a bunch of rectangles 57*cdf0e10cSrcweir // 58*cdf0e10cSrcweir // Helper functionality for sweep-line algorithm 59*cdf0e10cSrcweir // ==================================================== 60*cdf0e10cSrcweir 61*cdf0e10cSrcweir typedef std::vector<B2DRange> VectorOfRanges; 62*cdf0e10cSrcweir 63*cdf0e10cSrcweir class ImplPolygon; 64*cdf0e10cSrcweir typedef o3tl::vector_pool<ImplPolygon> VectorOfPolygons; 65*cdf0e10cSrcweir 66*cdf0e10cSrcweir 67*cdf0e10cSrcweir /** This class represents an active edge 68*cdf0e10cSrcweir 69*cdf0e10cSrcweir As the sweep line traverses across the overall area, 70*cdf0e10cSrcweir rectangle edges parallel to it generate events, and 71*cdf0e10cSrcweir rectangle edges orthogonal to it generate active 72*cdf0e10cSrcweir edges. This class represents the latter. 73*cdf0e10cSrcweir */ 74*cdf0e10cSrcweir class ActiveEdge 75*cdf0e10cSrcweir { 76*cdf0e10cSrcweir public: 77*cdf0e10cSrcweir /** The two possible active rectangle edges differ by one 78*cdf0e10cSrcweir coordinate value - the upper edge has the lower, the 79*cdf0e10cSrcweir lower edge the higher value. 80*cdf0e10cSrcweir */ 81*cdf0e10cSrcweir enum EdgeType { 82*cdf0e10cSrcweir /// edge with lower coordinate value 83*cdf0e10cSrcweir UPPER=0, 84*cdf0e10cSrcweir /// edge with higher coordinate value 85*cdf0e10cSrcweir LOWER=1 86*cdf0e10cSrcweir }; 87*cdf0e10cSrcweir 88*cdf0e10cSrcweir enum EdgeDirection { 89*cdf0e10cSrcweir /// edge proceeds to the left 90*cdf0e10cSrcweir PROCEED_LEFT=0, 91*cdf0e10cSrcweir /// edge proceeds to the right 92*cdf0e10cSrcweir PROCEED_RIGHT=1 93*cdf0e10cSrcweir }; 94*cdf0e10cSrcweir 95*cdf0e10cSrcweir /** Create active edge 96*cdf0e10cSrcweir 97*cdf0e10cSrcweir @param rRect 98*cdf0e10cSrcweir Rectangle this edge is part of 99*cdf0e10cSrcweir 100*cdf0e10cSrcweir @param fInvariantCoord 101*cdf0e10cSrcweir The invariant ccordinate value of this edge 102*cdf0e10cSrcweir 103*cdf0e10cSrcweir @param eEdgeType 104*cdf0e10cSrcweir Is fInvariantCoord the lower or the higher value, for 105*cdf0e10cSrcweir this rect? 106*cdf0e10cSrcweir */ 107*cdf0e10cSrcweir ActiveEdge( const B2DRectangle& rRect, 108*cdf0e10cSrcweir const double& fInvariantCoord, 109*cdf0e10cSrcweir std::ptrdiff_t nPolyIdx, 110*cdf0e10cSrcweir EdgeType eEdgeType, 111*cdf0e10cSrcweir EdgeDirection eEdgeDirection ) : 112*cdf0e10cSrcweir mfInvariantCoord(fInvariantCoord), 113*cdf0e10cSrcweir mpAssociatedRect( &rRect ), 114*cdf0e10cSrcweir mnPolygonIdx( nPolyIdx ), 115*cdf0e10cSrcweir meEdgeType( eEdgeType ), 116*cdf0e10cSrcweir meEdgeDirection( eEdgeDirection ) 117*cdf0e10cSrcweir {} 118*cdf0e10cSrcweir 119*cdf0e10cSrcweir double getInvariantCoord() const { return mfInvariantCoord; } 120*cdf0e10cSrcweir const B2DRectangle& getRect() const { return *mpAssociatedRect; } 121*cdf0e10cSrcweir std::ptrdiff_t getTargetPolygonIndex() const { return mnPolygonIdx; } 122*cdf0e10cSrcweir void setTargetPolygonIndex( std::ptrdiff_t nIdx ) { mnPolygonIdx = nIdx; } 123*cdf0e10cSrcweir EdgeType getEdgeType() const { return meEdgeType; } 124*cdf0e10cSrcweir EdgeDirection getEdgeDirection() const { return meEdgeDirection; } 125*cdf0e10cSrcweir 126*cdf0e10cSrcweir /// For STL sort 127*cdf0e10cSrcweir bool operator<( const ActiveEdge& rRHS ) const { return mfInvariantCoord < rRHS.mfInvariantCoord; } 128*cdf0e10cSrcweir 129*cdf0e10cSrcweir private: 130*cdf0e10cSrcweir /** The invariant coordinate value of this edge (e.g. the 131*cdf0e10cSrcweir common y value, for a horizontal edge) 132*cdf0e10cSrcweir */ 133*cdf0e10cSrcweir double mfInvariantCoord; 134*cdf0e10cSrcweir 135*cdf0e10cSrcweir /** Associated rectangle 136*cdf0e10cSrcweir 137*cdf0e10cSrcweir This on the one hand saves some storage space (the 138*cdf0e10cSrcweir vector of rectangles is persistent, anyway), and on 139*cdf0e10cSrcweir the other hand provides an identifier to match active 140*cdf0e10cSrcweir edges and x events (see below) 141*cdf0e10cSrcweir 142*cdf0e10cSrcweir Ptr because class needs to be assignable 143*cdf0e10cSrcweir */ 144*cdf0e10cSrcweir const B2DRectangle* mpAssociatedRect; 145*cdf0e10cSrcweir 146*cdf0e10cSrcweir /** Index of the polygon this edge is currently involved 147*cdf0e10cSrcweir with. 148*cdf0e10cSrcweir 149*cdf0e10cSrcweir Note that this can change for some kinds of edge 150*cdf0e10cSrcweir intersection, as the algorithm tends to swap 151*cdf0e10cSrcweir associated polygons there. 152*cdf0e10cSrcweir 153*cdf0e10cSrcweir -1 denotes no assigned polygon 154*cdf0e10cSrcweir */ 155*cdf0e10cSrcweir std::ptrdiff_t mnPolygonIdx; 156*cdf0e10cSrcweir 157*cdf0e10cSrcweir /// 'upper' or 'lower' edge of original rectangle. 158*cdf0e10cSrcweir EdgeType meEdgeType; 159*cdf0e10cSrcweir 160*cdf0e10cSrcweir /// 'left' or 'right' 161*cdf0e10cSrcweir EdgeDirection meEdgeDirection; 162*cdf0e10cSrcweir }; 163*cdf0e10cSrcweir 164*cdf0e10cSrcweir // Needs to be list - various places hold ptrs to elements 165*cdf0e10cSrcweir typedef std::list< ActiveEdge > ListOfEdges; 166*cdf0e10cSrcweir 167*cdf0e10cSrcweir 168*cdf0e10cSrcweir /** Element of the sweep line event list 169*cdf0e10cSrcweir 170*cdf0e10cSrcweir As the sweep line traverses across the overall area, 171*cdf0e10cSrcweir rectangle edges parallel to it generate events, and 172*cdf0e10cSrcweir rectangle edges orthogonal to it generate active 173*cdf0e10cSrcweir edges. This class represents the former. 174*cdf0e10cSrcweir 175*cdf0e10cSrcweir The class defines an element of the sweep line list. The 176*cdf0e10cSrcweir sweep line's position jumps in steps defined by the 177*cdf0e10cSrcweir coordinates of the sorted SweepLineEvent entries. 178*cdf0e10cSrcweir */ 179*cdf0e10cSrcweir class SweepLineEvent 180*cdf0e10cSrcweir { 181*cdf0e10cSrcweir public: 182*cdf0e10cSrcweir /** The two possible sweep line rectangle edges differ by 183*cdf0e10cSrcweir one coordinate value - the starting edge has the 184*cdf0e10cSrcweir lower, the finishing edge the higher value. 185*cdf0e10cSrcweir */ 186*cdf0e10cSrcweir enum EdgeType { 187*cdf0e10cSrcweir /// edge with lower coordinate value 188*cdf0e10cSrcweir STARTING_EDGE=0, 189*cdf0e10cSrcweir /// edge with higher coordinate value 190*cdf0e10cSrcweir FINISHING_EDGE=1 191*cdf0e10cSrcweir }; 192*cdf0e10cSrcweir 193*cdf0e10cSrcweir /** The two possible sweep line directions 194*cdf0e10cSrcweir */ 195*cdf0e10cSrcweir enum EdgeDirection { 196*cdf0e10cSrcweir PROCEED_UP=0, 197*cdf0e10cSrcweir PROCEED_DOWN=1 198*cdf0e10cSrcweir }; 199*cdf0e10cSrcweir 200*cdf0e10cSrcweir /** Create sweep line event 201*cdf0e10cSrcweir 202*cdf0e10cSrcweir @param fPos 203*cdf0e10cSrcweir Coordinate position of the event 204*cdf0e10cSrcweir 205*cdf0e10cSrcweir @param rRect 206*cdf0e10cSrcweir Rectangle this event is generated for. 207*cdf0e10cSrcweir 208*cdf0e10cSrcweir @param eEdgeType 209*cdf0e10cSrcweir Is fPos the lower or the higher value, for the 210*cdf0e10cSrcweir rectangle this event is generated for? 211*cdf0e10cSrcweir */ 212*cdf0e10cSrcweir SweepLineEvent( double fPos, 213*cdf0e10cSrcweir const B2DRectangle& rRect, 214*cdf0e10cSrcweir EdgeType eEdgeType, 215*cdf0e10cSrcweir EdgeDirection eDirection) : 216*cdf0e10cSrcweir mfPos( fPos ), 217*cdf0e10cSrcweir mpAssociatedRect( &rRect ), 218*cdf0e10cSrcweir meEdgeType( eEdgeType ), 219*cdf0e10cSrcweir meEdgeDirection( eDirection ) 220*cdf0e10cSrcweir {} 221*cdf0e10cSrcweir 222*cdf0e10cSrcweir double getPos() const { return mfPos; } 223*cdf0e10cSrcweir const B2DRectangle& getRect() const { return *mpAssociatedRect; } 224*cdf0e10cSrcweir EdgeType getEdgeType() const { return meEdgeType; } 225*cdf0e10cSrcweir EdgeDirection getEdgeDirection() const { return meEdgeDirection; } 226*cdf0e10cSrcweir 227*cdf0e10cSrcweir /// For STL sort 228*cdf0e10cSrcweir bool operator<( const SweepLineEvent& rRHS ) const { return mfPos < rRHS.mfPos; } 229*cdf0e10cSrcweir 230*cdf0e10cSrcweir private: 231*cdf0e10cSrcweir /// position of the event, in the direction of the line sweep 232*cdf0e10cSrcweir double mfPos; 233*cdf0e10cSrcweir 234*cdf0e10cSrcweir /** Rectangle this event is generated for 235*cdf0e10cSrcweir 236*cdf0e10cSrcweir This on the one hand saves some storage space (the 237*cdf0e10cSrcweir vector of rectangles is persistent, anyway), and on 238*cdf0e10cSrcweir the other hand provides an identifier to match active 239*cdf0e10cSrcweir edges and events (see below) 240*cdf0e10cSrcweir 241*cdf0e10cSrcweir Ptr because class needs to be assignable 242*cdf0e10cSrcweir */ 243*cdf0e10cSrcweir const B2DRectangle* mpAssociatedRect; 244*cdf0e10cSrcweir 245*cdf0e10cSrcweir /// 'upper' or 'lower' edge of original rectangle. 246*cdf0e10cSrcweir EdgeType meEdgeType; 247*cdf0e10cSrcweir 248*cdf0e10cSrcweir /// 'up' or 'down' 249*cdf0e10cSrcweir EdgeDirection meEdgeDirection; 250*cdf0e10cSrcweir }; 251*cdf0e10cSrcweir 252*cdf0e10cSrcweir typedef std::vector< SweepLineEvent > VectorOfEvents; 253*cdf0e10cSrcweir 254*cdf0e10cSrcweir 255*cdf0e10cSrcweir /** Smart point container for B2DMultiRange::getPolyPolygon() 256*cdf0e10cSrcweir 257*cdf0e10cSrcweir This class provides methods needed only here, and is used 258*cdf0e10cSrcweir as a place to store some additional information per 259*cdf0e10cSrcweir polygon. Also, most of the intersection logic is 260*cdf0e10cSrcweir implemented here. 261*cdf0e10cSrcweir */ 262*cdf0e10cSrcweir class ImplPolygon 263*cdf0e10cSrcweir { 264*cdf0e10cSrcweir public: 265*cdf0e10cSrcweir /** Create polygon 266*cdf0e10cSrcweir */ 267*cdf0e10cSrcweir ImplPolygon() : 268*cdf0e10cSrcweir mpLeadingRightEdge(NULL), 269*cdf0e10cSrcweir mnIdx(-1), 270*cdf0e10cSrcweir maPoints(), 271*cdf0e10cSrcweir mbIsFinished(false) 272*cdf0e10cSrcweir { 273*cdf0e10cSrcweir // completely ad-hoc. but what the hell. 274*cdf0e10cSrcweir maPoints.reserve(11); 275*cdf0e10cSrcweir } 276*cdf0e10cSrcweir 277*cdf0e10cSrcweir void setPolygonPoolIndex( std::ptrdiff_t nIdx ) { mnIdx = nIdx; } 278*cdf0e10cSrcweir bool isFinished() const { return mbIsFinished; } 279*cdf0e10cSrcweir 280*cdf0e10cSrcweir /// Add point to the end of the existing points 281*cdf0e10cSrcweir void append( const B2DPoint& rPoint ) 282*cdf0e10cSrcweir { 283*cdf0e10cSrcweir OSL_PRECOND( maPoints.empty() || 284*cdf0e10cSrcweir maPoints.back().getX() == rPoint.getX() || 285*cdf0e10cSrcweir maPoints.back().getY() == rPoint.getY(), 286*cdf0e10cSrcweir "ImplPolygon::append(): added point violates 90 degree line angle constraint!" ); 287*cdf0e10cSrcweir 288*cdf0e10cSrcweir if( maPoints.empty() || 289*cdf0e10cSrcweir maPoints.back() != rPoint ) 290*cdf0e10cSrcweir { 291*cdf0e10cSrcweir // avoid duplicate points 292*cdf0e10cSrcweir maPoints.push_back( rPoint ); 293*cdf0e10cSrcweir } 294*cdf0e10cSrcweir } 295*cdf0e10cSrcweir 296*cdf0e10cSrcweir /** Perform the intersection of this polygon with an 297*cdf0e10cSrcweir active edge. 298*cdf0e10cSrcweir 299*cdf0e10cSrcweir @param rEvent 300*cdf0e10cSrcweir The vertical line event that generated the 301*cdf0e10cSrcweir intersection 302*cdf0e10cSrcweir 303*cdf0e10cSrcweir @param rActiveEdge 304*cdf0e10cSrcweir The active edge that generated the intersection 305*cdf0e10cSrcweir 306*cdf0e10cSrcweir @param rPolygonPool 307*cdf0e10cSrcweir Polygon pool, we sometimes need to allocate a new one 308*cdf0e10cSrcweir 309*cdf0e10cSrcweir @param bIsFinishingEdge 310*cdf0e10cSrcweir True, when this is hitting the last edge of the 311*cdf0e10cSrcweir vertical sweep - every vertical sweep starts and ends 312*cdf0e10cSrcweir with upper and lower edge of the _same_ rectangle. 313*cdf0e10cSrcweir 314*cdf0e10cSrcweir @return the new current polygon (that's the one 315*cdf0e10cSrcweir processing must proceed with, when going through the 316*cdf0e10cSrcweir list of upcoming active edges). 317*cdf0e10cSrcweir */ 318*cdf0e10cSrcweir std::ptrdiff_t intersect( SweepLineEvent& rEvent, 319*cdf0e10cSrcweir ActiveEdge& rActiveEdge, 320*cdf0e10cSrcweir VectorOfPolygons& rPolygonPool, 321*cdf0e10cSrcweir B2DPolyPolygon& rRes, 322*cdf0e10cSrcweir bool isFinishingEdge ) 323*cdf0e10cSrcweir { 324*cdf0e10cSrcweir OSL_PRECOND( !isFinished(), 325*cdf0e10cSrcweir "ImplPolygon::intersect(): called on already finished polygon!" ); 326*cdf0e10cSrcweir OSL_PRECOND( !isFinishingEdge 327*cdf0e10cSrcweir || (isFinishingEdge && &rEvent.getRect() == &rActiveEdge.getRect()), 328*cdf0e10cSrcweir "ImplPolygon::intersect(): inconsistent ending!" ); 329*cdf0e10cSrcweir 330*cdf0e10cSrcweir const B2DPoint aIntersectionPoint( rEvent.getPos(), 331*cdf0e10cSrcweir rActiveEdge.getInvariantCoord() ); 332*cdf0e10cSrcweir 333*cdf0e10cSrcweir // intersection point, goes to our polygon 334*cdf0e10cSrcweir // unconditionally 335*cdf0e10cSrcweir append(aIntersectionPoint); 336*cdf0e10cSrcweir 337*cdf0e10cSrcweir const bool isSweepLineEnteringRect( 338*cdf0e10cSrcweir rEvent.getEdgeType() == SweepLineEvent::STARTING_EDGE); 339*cdf0e10cSrcweir if( isFinishingEdge ) 340*cdf0e10cSrcweir { 341*cdf0e10cSrcweir if( isSweepLineEnteringRect ) 342*cdf0e10cSrcweir handleFinalOwnRightEdge(rActiveEdge); 343*cdf0e10cSrcweir else 344*cdf0e10cSrcweir handleFinalOwnLeftEdge(rActiveEdge, 345*cdf0e10cSrcweir rPolygonPool, 346*cdf0e10cSrcweir rRes); 347*cdf0e10cSrcweir 348*cdf0e10cSrcweir // we're done with this rect & sweep line 349*cdf0e10cSrcweir return -1; 350*cdf0e10cSrcweir } 351*cdf0e10cSrcweir else if( metOwnEdge(rEvent,rActiveEdge) ) 352*cdf0e10cSrcweir { 353*cdf0e10cSrcweir handleInitialOwnEdge(rEvent, rActiveEdge); 354*cdf0e10cSrcweir 355*cdf0e10cSrcweir // point already added, all init done, continue 356*cdf0e10cSrcweir // with same poly 357*cdf0e10cSrcweir return mnIdx; 358*cdf0e10cSrcweir } 359*cdf0e10cSrcweir else 360*cdf0e10cSrcweir { 361*cdf0e10cSrcweir OSL_ENSURE( rActiveEdge.getTargetPolygonIndex() != -1, 362*cdf0e10cSrcweir "ImplPolygon::intersect(): non-trivial intersection hit empty polygon!" ); 363*cdf0e10cSrcweir 364*cdf0e10cSrcweir const bool isHittingLeftEdge( 365*cdf0e10cSrcweir rActiveEdge.getEdgeDirection() == ActiveEdge::PROCEED_LEFT); 366*cdf0e10cSrcweir 367*cdf0e10cSrcweir if( isHittingLeftEdge ) 368*cdf0e10cSrcweir return handleComplexLeftEdge(rActiveEdge, 369*cdf0e10cSrcweir aIntersectionPoint, 370*cdf0e10cSrcweir rPolygonPool, 371*cdf0e10cSrcweir rRes); 372*cdf0e10cSrcweir else 373*cdf0e10cSrcweir return handleComplexRightEdge(rActiveEdge, 374*cdf0e10cSrcweir aIntersectionPoint, 375*cdf0e10cSrcweir rPolygonPool); 376*cdf0e10cSrcweir } 377*cdf0e10cSrcweir } 378*cdf0e10cSrcweir 379*cdf0e10cSrcweir private: 380*cdf0e10cSrcweir std::ptrdiff_t getPolygonPoolIndex() const { return mnIdx; } 381*cdf0e10cSrcweir 382*cdf0e10cSrcweir void handleInitialOwnEdge(SweepLineEvent& rEvent, 383*cdf0e10cSrcweir ActiveEdge& rActiveEdge) 384*cdf0e10cSrcweir { 385*cdf0e10cSrcweir const bool isActiveEdgeProceedLeft( 386*cdf0e10cSrcweir rActiveEdge.getEdgeDirection() == ActiveEdge::PROCEED_LEFT); 387*cdf0e10cSrcweir const bool isSweepLineEnteringRect( 388*cdf0e10cSrcweir rEvent.getEdgeType() == SweepLineEvent::STARTING_EDGE); 389*cdf0e10cSrcweir (void)isActiveEdgeProceedLeft; 390*cdf0e10cSrcweir (void)isSweepLineEnteringRect; 391*cdf0e10cSrcweir 392*cdf0e10cSrcweir OSL_ENSURE( isSweepLineEnteringRect == isActiveEdgeProceedLeft, 393*cdf0e10cSrcweir "ImplPolygon::intersect(): sweep initial own edge hit: wrong polygon order" ); 394*cdf0e10cSrcweir 395*cdf0e10cSrcweir OSL_ENSURE( isSweepLineEnteringRect || 396*cdf0e10cSrcweir mpLeadingRightEdge == &rActiveEdge, 397*cdf0e10cSrcweir "ImplPolygon::intersect(): sweep initial own edge hit: wrong leading edge" ); 398*cdf0e10cSrcweir } 399*cdf0e10cSrcweir 400*cdf0e10cSrcweir void handleFinalOwnRightEdge(ActiveEdge& rActiveEdge) 401*cdf0e10cSrcweir { 402*cdf0e10cSrcweir OSL_ENSURE( rActiveEdge.getEdgeDirection() == ActiveEdge::PROCEED_RIGHT, 403*cdf0e10cSrcweir "ImplPolygon::handleInitialOwnRightEdge(): start edge wrong polygon order" ); 404*cdf0e10cSrcweir 405*cdf0e10cSrcweir rActiveEdge.setTargetPolygonIndex(mnIdx); 406*cdf0e10cSrcweir mpLeadingRightEdge = &rActiveEdge; 407*cdf0e10cSrcweir } 408*cdf0e10cSrcweir 409*cdf0e10cSrcweir void handleFinalOwnLeftEdge(ActiveEdge& rActiveEdge, 410*cdf0e10cSrcweir VectorOfPolygons& rPolygonPool, 411*cdf0e10cSrcweir B2DPolyPolygon& rRes) 412*cdf0e10cSrcweir { 413*cdf0e10cSrcweir OSL_ENSURE( rActiveEdge.getEdgeDirection() == ActiveEdge::PROCEED_LEFT, 414*cdf0e10cSrcweir "ImplPolygon::handleFinalOwnLeftEdge(): end edge wrong polygon order" ); 415*cdf0e10cSrcweir 416*cdf0e10cSrcweir const bool isHittingOurTail( 417*cdf0e10cSrcweir rActiveEdge.getTargetPolygonIndex() == mnIdx); 418*cdf0e10cSrcweir 419*cdf0e10cSrcweir if( isHittingOurTail ) 420*cdf0e10cSrcweir finish(rRes); // just finish. no fuss. 421*cdf0e10cSrcweir else 422*cdf0e10cSrcweir { 423*cdf0e10cSrcweir // temp poly hits final left edge 424*cdf0e10cSrcweir const std::ptrdiff_t nTmpIdx=rActiveEdge.getTargetPolygonIndex(); 425*cdf0e10cSrcweir ImplPolygon& rTmp=rPolygonPool.get(nTmpIdx); 426*cdf0e10cSrcweir 427*cdf0e10cSrcweir // active edge's polygon has points 428*cdf0e10cSrcweir // already. ours need to go in front of them. 429*cdf0e10cSrcweir maPoints.insert(maPoints.end(), 430*cdf0e10cSrcweir rTmp.maPoints.begin(), 431*cdf0e10cSrcweir rTmp.maPoints.end()); 432*cdf0e10cSrcweir 433*cdf0e10cSrcweir // adjust leading edges, we're switching the polygon 434*cdf0e10cSrcweir ActiveEdge* const pFarEdge=rTmp.mpLeadingRightEdge; 435*cdf0e10cSrcweir 436*cdf0e10cSrcweir mpLeadingRightEdge = pFarEdge; 437*cdf0e10cSrcweir pFarEdge->setTargetPolygonIndex(mnIdx); 438*cdf0e10cSrcweir 439*cdf0e10cSrcweir // nTmpIdx is an empty shell, get rid of it 440*cdf0e10cSrcweir rPolygonPool.free(nTmpIdx); 441*cdf0e10cSrcweir } 442*cdf0e10cSrcweir } 443*cdf0e10cSrcweir 444*cdf0e10cSrcweir std::ptrdiff_t handleComplexLeftEdge(ActiveEdge& rActiveEdge, 445*cdf0e10cSrcweir const B2DPoint& rIntersectionPoint, 446*cdf0e10cSrcweir VectorOfPolygons& rPolygonPool, 447*cdf0e10cSrcweir B2DPolyPolygon& rRes) 448*cdf0e10cSrcweir { 449*cdf0e10cSrcweir const bool isHittingOurTail( 450*cdf0e10cSrcweir rActiveEdge.getTargetPolygonIndex() == mnIdx); 451*cdf0e10cSrcweir if( isHittingOurTail ) 452*cdf0e10cSrcweir { 453*cdf0e10cSrcweir finish(rRes); 454*cdf0e10cSrcweir 455*cdf0e10cSrcweir // so "this" is done - need new polygon to collect 456*cdf0e10cSrcweir // further points 457*cdf0e10cSrcweir const std::ptrdiff_t nIdxNewPolygon=rPolygonPool.alloc(); 458*cdf0e10cSrcweir rPolygonPool.get(nIdxNewPolygon).setPolygonPoolIndex(nIdxNewPolygon); 459*cdf0e10cSrcweir rPolygonPool.get(nIdxNewPolygon).append(rIntersectionPoint); 460*cdf0e10cSrcweir 461*cdf0e10cSrcweir rActiveEdge.setTargetPolygonIndex(nIdxNewPolygon); 462*cdf0e10cSrcweir 463*cdf0e10cSrcweir return nIdxNewPolygon; 464*cdf0e10cSrcweir } 465*cdf0e10cSrcweir else 466*cdf0e10cSrcweir { 467*cdf0e10cSrcweir const std::ptrdiff_t nTmpIdx=rActiveEdge.getTargetPolygonIndex(); 468*cdf0e10cSrcweir ImplPolygon& rTmp=rPolygonPool.get(nTmpIdx); 469*cdf0e10cSrcweir 470*cdf0e10cSrcweir // active edge's polygon has points 471*cdf0e10cSrcweir // already. ours need to go in front of them. 472*cdf0e10cSrcweir maPoints.insert(maPoints.end(), 473*cdf0e10cSrcweir rTmp.maPoints.begin(), 474*cdf0e10cSrcweir rTmp.maPoints.end()); 475*cdf0e10cSrcweir 476*cdf0e10cSrcweir rTmp.maPoints.clear(); 477*cdf0e10cSrcweir rTmp.append(rIntersectionPoint); 478*cdf0e10cSrcweir 479*cdf0e10cSrcweir // adjust leading edges, we're switching the polygon 480*cdf0e10cSrcweir ActiveEdge* const pFarEdge=rTmp.mpLeadingRightEdge; 481*cdf0e10cSrcweir ActiveEdge* const pNearEdge=&rActiveEdge; 482*cdf0e10cSrcweir 483*cdf0e10cSrcweir rTmp.mpLeadingRightEdge = NULL; 484*cdf0e10cSrcweir pNearEdge->setTargetPolygonIndex(nTmpIdx); 485*cdf0e10cSrcweir 486*cdf0e10cSrcweir mpLeadingRightEdge = pFarEdge; 487*cdf0e10cSrcweir pFarEdge->setTargetPolygonIndex(mnIdx); 488*cdf0e10cSrcweir 489*cdf0e10cSrcweir return nTmpIdx; 490*cdf0e10cSrcweir } 491*cdf0e10cSrcweir } 492*cdf0e10cSrcweir 493*cdf0e10cSrcweir std::ptrdiff_t handleComplexRightEdge(ActiveEdge& rActiveEdge, 494*cdf0e10cSrcweir const B2DPoint& rIntersectionPoint, 495*cdf0e10cSrcweir VectorOfPolygons& rPolygonPool) 496*cdf0e10cSrcweir { 497*cdf0e10cSrcweir const std::ptrdiff_t nTmpIdx=rActiveEdge.getTargetPolygonIndex(); 498*cdf0e10cSrcweir ImplPolygon& rTmp=rPolygonPool.get(nTmpIdx); 499*cdf0e10cSrcweir 500*cdf0e10cSrcweir rTmp.append(rIntersectionPoint); 501*cdf0e10cSrcweir 502*cdf0e10cSrcweir rActiveEdge.setTargetPolygonIndex(mnIdx); 503*cdf0e10cSrcweir mpLeadingRightEdge = &rActiveEdge; 504*cdf0e10cSrcweir 505*cdf0e10cSrcweir rTmp.mpLeadingRightEdge = NULL; 506*cdf0e10cSrcweir 507*cdf0e10cSrcweir return nTmpIdx; 508*cdf0e10cSrcweir } 509*cdf0e10cSrcweir 510*cdf0e10cSrcweir /// True when sweep line hits our own active edge 511*cdf0e10cSrcweir bool metOwnEdge(const SweepLineEvent& rEvent, 512*cdf0e10cSrcweir ActiveEdge& rActiveEdge) 513*cdf0e10cSrcweir { 514*cdf0e10cSrcweir const bool bHitOwnEdge=&rEvent.getRect() == &rActiveEdge.getRect(); 515*cdf0e10cSrcweir return bHitOwnEdge; 516*cdf0e10cSrcweir } 517*cdf0e10cSrcweir 518*cdf0e10cSrcweir /// Retrieve B2DPolygon from this object 519*cdf0e10cSrcweir B2DPolygon getPolygon() const 520*cdf0e10cSrcweir { 521*cdf0e10cSrcweir B2DPolygon aRes; 522*cdf0e10cSrcweir std::for_each( maPoints.begin(), 523*cdf0e10cSrcweir maPoints.end(), 524*cdf0e10cSrcweir boost::bind( 525*cdf0e10cSrcweir &B2DPolygon::append, 526*cdf0e10cSrcweir boost::ref(aRes), 527*cdf0e10cSrcweir _1, 528*cdf0e10cSrcweir 1 ) ); 529*cdf0e10cSrcweir aRes.setClosed( true ); 530*cdf0e10cSrcweir return aRes; 531*cdf0e10cSrcweir } 532*cdf0e10cSrcweir 533*cdf0e10cSrcweir /** Finish this polygon, push to result set. 534*cdf0e10cSrcweir */ 535*cdf0e10cSrcweir void finish(B2DPolyPolygon& rRes) 536*cdf0e10cSrcweir { 537*cdf0e10cSrcweir OSL_PRECOND( maPoints.empty() || 538*cdf0e10cSrcweir maPoints.front().getX() == maPoints.back().getX() || 539*cdf0e10cSrcweir maPoints.front().getY() == maPoints.back().getY(), 540*cdf0e10cSrcweir "ImplPolygon::finish(): first and last point violate 90 degree line angle constraint!" ); 541*cdf0e10cSrcweir 542*cdf0e10cSrcweir mbIsFinished = true; 543*cdf0e10cSrcweir mpLeadingRightEdge = NULL; 544*cdf0e10cSrcweir 545*cdf0e10cSrcweir rRes.append(getPolygon()); 546*cdf0e10cSrcweir } 547*cdf0e10cSrcweir 548*cdf0e10cSrcweir /** Refers to the current leading edge element of this 549*cdf0e10cSrcweir polygon, or NULL. The leading edge denotes the 'front' 550*cdf0e10cSrcweir of the polygon vertex sequence, i.e. the coordinates 551*cdf0e10cSrcweir at the polygon's leading edge are returned from 552*cdf0e10cSrcweir maPoints.front() 553*cdf0e10cSrcweir */ 554*cdf0e10cSrcweir ActiveEdge* mpLeadingRightEdge; 555*cdf0e10cSrcweir 556*cdf0e10cSrcweir /// current index into vector pool 557*cdf0e10cSrcweir std::ptrdiff_t mnIdx; 558*cdf0e10cSrcweir 559*cdf0e10cSrcweir /// Container for the actual polygon points 560*cdf0e10cSrcweir std::vector<B2DPoint> maPoints; 561*cdf0e10cSrcweir 562*cdf0e10cSrcweir /// When true, this polygon is 'done', i.e. nothing must be added anymore. 563*cdf0e10cSrcweir bool mbIsFinished; 564*cdf0e10cSrcweir }; 565*cdf0e10cSrcweir 566*cdf0e10cSrcweir /** Init sweep line event list 567*cdf0e10cSrcweir 568*cdf0e10cSrcweir This method fills the event list with the sweep line 569*cdf0e10cSrcweir events generated from the input rectangles, and sorts them 570*cdf0e10cSrcweir with increasing x. 571*cdf0e10cSrcweir */ 572*cdf0e10cSrcweir void setupSweepLineEventListFromRanges( VectorOfEvents& o_rEventVector, 573*cdf0e10cSrcweir const std::vector<B2DRange>& rRanges, 574*cdf0e10cSrcweir const std::vector<B2VectorOrientation>& rOrientations ) 575*cdf0e10cSrcweir { 576*cdf0e10cSrcweir // we need exactly 2*rectVec.size() events: one for the 577*cdf0e10cSrcweir // left, and one for the right edge of each rectangle 578*cdf0e10cSrcweir o_rEventVector.clear(); 579*cdf0e10cSrcweir o_rEventVector.reserve( 2*rRanges.size() ); 580*cdf0e10cSrcweir 581*cdf0e10cSrcweir // generate events 582*cdf0e10cSrcweir // =============== 583*cdf0e10cSrcweir 584*cdf0e10cSrcweir // first pass: add all left edges in increasing order 585*cdf0e10cSrcweir std::vector<B2DRange>::const_iterator aCurrRect=rRanges.begin(); 586*cdf0e10cSrcweir std::vector<B2VectorOrientation>::const_iterator aCurrOrientation=rOrientations.begin(); 587*cdf0e10cSrcweir const std::vector<B2DRange>::const_iterator aEnd=rRanges.end(); 588*cdf0e10cSrcweir const std::vector<B2VectorOrientation>::const_iterator aEndOrientation=rOrientations.end(); 589*cdf0e10cSrcweir while( aCurrRect != aEnd && aCurrOrientation != aEndOrientation ) 590*cdf0e10cSrcweir { 591*cdf0e10cSrcweir const B2DRectangle& rCurrRect( *aCurrRect++ ); 592*cdf0e10cSrcweir 593*cdf0e10cSrcweir o_rEventVector.push_back( 594*cdf0e10cSrcweir SweepLineEvent( rCurrRect.getMinX(), 595*cdf0e10cSrcweir rCurrRect, 596*cdf0e10cSrcweir SweepLineEvent::STARTING_EDGE, 597*cdf0e10cSrcweir (*aCurrOrientation++) == ORIENTATION_POSITIVE ? 598*cdf0e10cSrcweir SweepLineEvent::PROCEED_UP : SweepLineEvent::PROCEED_DOWN) ); 599*cdf0e10cSrcweir } 600*cdf0e10cSrcweir 601*cdf0e10cSrcweir // second pass: add all right edges in reversed order 602*cdf0e10cSrcweir std::vector<B2DRange>::const_reverse_iterator aCurrRectR=rRanges.rbegin(); 603*cdf0e10cSrcweir std::vector<B2VectorOrientation>::const_reverse_iterator aCurrOrientationR=rOrientations.rbegin(); 604*cdf0e10cSrcweir const std::vector<B2DRange>::const_reverse_iterator aEndR=rRanges.rend(); 605*cdf0e10cSrcweir const std::vector<B2VectorOrientation>::const_reverse_iterator aEndOrientationR=rOrientations.rend(); 606*cdf0e10cSrcweir while( aCurrRectR != aEndR ) 607*cdf0e10cSrcweir { 608*cdf0e10cSrcweir const B2DRectangle& rCurrRect( *aCurrRectR++ ); 609*cdf0e10cSrcweir 610*cdf0e10cSrcweir o_rEventVector.push_back( 611*cdf0e10cSrcweir SweepLineEvent( rCurrRect.getMaxX(), 612*cdf0e10cSrcweir rCurrRect, 613*cdf0e10cSrcweir SweepLineEvent::FINISHING_EDGE, 614*cdf0e10cSrcweir (*aCurrOrientationR++) == ORIENTATION_POSITIVE ? 615*cdf0e10cSrcweir SweepLineEvent::PROCEED_DOWN : SweepLineEvent::PROCEED_UP ) ); 616*cdf0e10cSrcweir } 617*cdf0e10cSrcweir 618*cdf0e10cSrcweir // sort events 619*cdf0e10cSrcweir // =========== 620*cdf0e10cSrcweir 621*cdf0e10cSrcweir // since we use stable_sort, the order of events with the 622*cdf0e10cSrcweir // same x value will not change. The elaborate two-pass 623*cdf0e10cSrcweir // add above thus ensures, that for each two rectangles 624*cdf0e10cSrcweir // with similar left and right x coordinates, the 625*cdf0e10cSrcweir // rectangle whose left event comes first will have its 626*cdf0e10cSrcweir // right event come last. This is advantageous for the 627*cdf0e10cSrcweir // clip algorithm below, see handleRightEdgeCrossing(). 628*cdf0e10cSrcweir 629*cdf0e10cSrcweir // TODO(P3): Use radix sort (from 630*cdf0e10cSrcweir // b2dpolypolygonrasterconverter, or have your own 631*cdf0e10cSrcweir // templatized version). 632*cdf0e10cSrcweir std::stable_sort( o_rEventVector.begin(), 633*cdf0e10cSrcweir o_rEventVector.end() ); 634*cdf0e10cSrcweir } 635*cdf0e10cSrcweir 636*cdf0e10cSrcweir /** Insert two active edge segments for the given rectangle. 637*cdf0e10cSrcweir 638*cdf0e10cSrcweir This method creates two active edge segments from the 639*cdf0e10cSrcweir given rect, and inserts them into the active edge list, 640*cdf0e10cSrcweir such that this stays sorted (if it was before). 641*cdf0e10cSrcweir 642*cdf0e10cSrcweir @param io_rEdgeList 643*cdf0e10cSrcweir Active edge list to insert into 644*cdf0e10cSrcweir 645*cdf0e10cSrcweir @param io_rPolygons 646*cdf0e10cSrcweir Vector of polygons. Each rectangle added creates one 647*cdf0e10cSrcweir tentative result polygon in this vector, and the edge list 648*cdf0e10cSrcweir entries holds a reference to that polygon (this _requires_ 649*cdf0e10cSrcweir that the polygon vector does not reallocate, i.e. it must 650*cdf0e10cSrcweir have at least the maximal number of rectangles reserved) 651*cdf0e10cSrcweir 652*cdf0e10cSrcweir @param o_CurrentPolygon 653*cdf0e10cSrcweir The then-current polygon when processing this sweep line 654*cdf0e10cSrcweir event 655*cdf0e10cSrcweir 656*cdf0e10cSrcweir @param rCurrEvent 657*cdf0e10cSrcweir The actual event that caused this call 658*cdf0e10cSrcweir */ 659*cdf0e10cSrcweir void createActiveEdgesFromStartEvent( ListOfEdges& io_rEdgeList, 660*cdf0e10cSrcweir VectorOfPolygons& io_rPolygonPool, 661*cdf0e10cSrcweir SweepLineEvent& rCurrEvent ) 662*cdf0e10cSrcweir { 663*cdf0e10cSrcweir ListOfEdges aNewEdges; 664*cdf0e10cSrcweir const B2DRectangle& rRect=rCurrEvent.getRect(); 665*cdf0e10cSrcweir const bool bGoesDown=rCurrEvent.getEdgeDirection() == SweepLineEvent::PROCEED_DOWN; 666*cdf0e10cSrcweir 667*cdf0e10cSrcweir // start event - new rect starts here, needs polygon to 668*cdf0e10cSrcweir // collect points into 669*cdf0e10cSrcweir const std::ptrdiff_t nIdxPolygon=io_rPolygonPool.alloc(); 670*cdf0e10cSrcweir io_rPolygonPool.get(nIdxPolygon).setPolygonPoolIndex(nIdxPolygon); 671*cdf0e10cSrcweir 672*cdf0e10cSrcweir // upper edge 673*cdf0e10cSrcweir aNewEdges.push_back( 674*cdf0e10cSrcweir ActiveEdge( 675*cdf0e10cSrcweir rRect, 676*cdf0e10cSrcweir rRect.getMinY(), 677*cdf0e10cSrcweir bGoesDown ? nIdxPolygon : -1, 678*cdf0e10cSrcweir ActiveEdge::UPPER, 679*cdf0e10cSrcweir bGoesDown ? ActiveEdge::PROCEED_LEFT : ActiveEdge::PROCEED_RIGHT) ); 680*cdf0e10cSrcweir // lower edge 681*cdf0e10cSrcweir aNewEdges.push_back( 682*cdf0e10cSrcweir ActiveEdge( 683*cdf0e10cSrcweir rRect, 684*cdf0e10cSrcweir rRect.getMaxY(), 685*cdf0e10cSrcweir bGoesDown ? -1 : nIdxPolygon, 686*cdf0e10cSrcweir ActiveEdge::LOWER, 687*cdf0e10cSrcweir bGoesDown ? ActiveEdge::PROCEED_RIGHT : ActiveEdge::PROCEED_LEFT ) ); 688*cdf0e10cSrcweir 689*cdf0e10cSrcweir // furthermore, have to respect a special tie-breaking 690*cdf0e10cSrcweir // rule here, for edges which share the same y value: 691*cdf0e10cSrcweir // newly added upper edges must be inserted _before_ any 692*cdf0e10cSrcweir // other edge with the same y value, and newly added lower 693*cdf0e10cSrcweir // edges must be _after_ all other edges with the same 694*cdf0e10cSrcweir // y. This ensures that the left vertical edge processing 695*cdf0e10cSrcweir // below encounters the upper edge of the current rect 696*cdf0e10cSrcweir // first, and the lower edge last, which automatically 697*cdf0e10cSrcweir // starts and finishes this rect correctly (as only then, 698*cdf0e10cSrcweir // the polygon will have their associated active edges 699*cdf0e10cSrcweir // set). 700*cdf0e10cSrcweir const double nMinY( rRect.getMinY() ); 701*cdf0e10cSrcweir const double nMaxY( rRect.getMaxY() ); 702*cdf0e10cSrcweir ListOfEdges::iterator aCurr( io_rEdgeList.begin() ); 703*cdf0e10cSrcweir const ListOfEdges::iterator aEnd ( io_rEdgeList.end() ); 704*cdf0e10cSrcweir while( aCurr != aEnd ) 705*cdf0e10cSrcweir { 706*cdf0e10cSrcweir const double nCurrY( aCurr->getInvariantCoord() ); 707*cdf0e10cSrcweir 708*cdf0e10cSrcweir if( nCurrY >= nMinY && 709*cdf0e10cSrcweir aNewEdges.size() == 2 ) // only add, if not yet done. 710*cdf0e10cSrcweir { 711*cdf0e10cSrcweir // insert upper edge _before_ aCurr. Thus, it will 712*cdf0e10cSrcweir // be the first entry for a range of equal y 713*cdf0e10cSrcweir // values. Using splice here, since we hold 714*cdf0e10cSrcweir // references to the moved list element! 715*cdf0e10cSrcweir io_rEdgeList.splice( aCurr, 716*cdf0e10cSrcweir aNewEdges, 717*cdf0e10cSrcweir aNewEdges.begin() ); 718*cdf0e10cSrcweir } 719*cdf0e10cSrcweir 720*cdf0e10cSrcweir if( nCurrY > nMaxY ) 721*cdf0e10cSrcweir { 722*cdf0e10cSrcweir // insert lower edge _before_ aCurr. Thus, it will 723*cdf0e10cSrcweir // be the last entry for a range of equal y values 724*cdf0e10cSrcweir // (aCurr is the first entry strictly larger than 725*cdf0e10cSrcweir // nMaxY). Using splice here, since we hold 726*cdf0e10cSrcweir // references to the moved list element! 727*cdf0e10cSrcweir io_rEdgeList.splice( aCurr, 728*cdf0e10cSrcweir aNewEdges, 729*cdf0e10cSrcweir aNewEdges.begin() ); 730*cdf0e10cSrcweir // done with insertion, can early-exit here. 731*cdf0e10cSrcweir return; 732*cdf0e10cSrcweir } 733*cdf0e10cSrcweir 734*cdf0e10cSrcweir ++aCurr; 735*cdf0e10cSrcweir } 736*cdf0e10cSrcweir 737*cdf0e10cSrcweir // append remainder of aNewList (might still contain 2 or 738*cdf0e10cSrcweir // 1 elements, depending of the contents of io_rEdgeList). 739*cdf0e10cSrcweir io_rEdgeList.splice( aCurr, 740*cdf0e10cSrcweir aNewEdges ); 741*cdf0e10cSrcweir } 742*cdf0e10cSrcweir 743*cdf0e10cSrcweir inline bool isSameRect(ActiveEdge& rEdge, 744*cdf0e10cSrcweir const basegfx::B2DRange& rRect) 745*cdf0e10cSrcweir { 746*cdf0e10cSrcweir return &rEdge.getRect() == &rRect; 747*cdf0e10cSrcweir } 748*cdf0e10cSrcweir 749*cdf0e10cSrcweir // wow what a hack. necessary because stl's list::erase does 750*cdf0e10cSrcweir // not eat reverse_iterator 751*cdf0e10cSrcweir template<typename Cont, typename Iter> Iter eraseFromList(Cont&, Iter); 752*cdf0e10cSrcweir template<> inline ListOfEdges::iterator eraseFromList( 753*cdf0e10cSrcweir ListOfEdges& rList, ListOfEdges::iterator aIter) 754*cdf0e10cSrcweir { 755*cdf0e10cSrcweir return rList.erase(aIter); 756*cdf0e10cSrcweir } 757*cdf0e10cSrcweir template<> inline ListOfEdges::reverse_iterator eraseFromList( 758*cdf0e10cSrcweir ListOfEdges& rList, ListOfEdges::reverse_iterator aIter) 759*cdf0e10cSrcweir { 760*cdf0e10cSrcweir return ListOfEdges::reverse_iterator( 761*cdf0e10cSrcweir rList.erase(boost::prior(aIter.base()))); 762*cdf0e10cSrcweir } 763*cdf0e10cSrcweir 764*cdf0e10cSrcweir template<int bPerformErase, 765*cdf0e10cSrcweir typename Iterator> inline void processActiveEdges( 766*cdf0e10cSrcweir Iterator first, 767*cdf0e10cSrcweir Iterator last, 768*cdf0e10cSrcweir ListOfEdges& rActiveEdgeList, 769*cdf0e10cSrcweir SweepLineEvent& rCurrEvent, 770*cdf0e10cSrcweir VectorOfPolygons& rPolygonPool, 771*cdf0e10cSrcweir B2DPolyPolygon& rRes ) 772*cdf0e10cSrcweir { 773*cdf0e10cSrcweir const basegfx::B2DRange& rCurrRect=rCurrEvent.getRect(); 774*cdf0e10cSrcweir 775*cdf0e10cSrcweir // fast-forward to rCurrEvent's first active edge (holds 776*cdf0e10cSrcweir // for both starting and finishing sweep line events, a 777*cdf0e10cSrcweir // rect is regarded _outside_ any rects whose events have 778*cdf0e10cSrcweir // started earlier 779*cdf0e10cSrcweir first = std::find_if(first, last, 780*cdf0e10cSrcweir boost::bind( 781*cdf0e10cSrcweir &isSameRect, 782*cdf0e10cSrcweir _1, 783*cdf0e10cSrcweir boost::cref(rCurrRect))); 784*cdf0e10cSrcweir 785*cdf0e10cSrcweir if(first == last) 786*cdf0e10cSrcweir return; 787*cdf0e10cSrcweir 788*cdf0e10cSrcweir int nCount=0; 789*cdf0e10cSrcweir std::ptrdiff_t nCurrPolyIdx=-1; 790*cdf0e10cSrcweir while(first != last) 791*cdf0e10cSrcweir { 792*cdf0e10cSrcweir if( nCurrPolyIdx == -1 ) 793*cdf0e10cSrcweir nCurrPolyIdx=first->getTargetPolygonIndex(); 794*cdf0e10cSrcweir 795*cdf0e10cSrcweir OSL_ASSERT(nCurrPolyIdx != -1); 796*cdf0e10cSrcweir 797*cdf0e10cSrcweir // second encounter of my rect -> second edge 798*cdf0e10cSrcweir // encountered, done 799*cdf0e10cSrcweir const bool bExit= 800*cdf0e10cSrcweir nCount && 801*cdf0e10cSrcweir isSameRect(*first, 802*cdf0e10cSrcweir rCurrRect); 803*cdf0e10cSrcweir 804*cdf0e10cSrcweir // deal with current active edge 805*cdf0e10cSrcweir nCurrPolyIdx = 806*cdf0e10cSrcweir rPolygonPool.get(nCurrPolyIdx).intersect( 807*cdf0e10cSrcweir rCurrEvent, 808*cdf0e10cSrcweir *first, 809*cdf0e10cSrcweir rPolygonPool, 810*cdf0e10cSrcweir rRes, 811*cdf0e10cSrcweir bExit); 812*cdf0e10cSrcweir 813*cdf0e10cSrcweir // prune upper & lower active edges, if requested 814*cdf0e10cSrcweir if( bPerformErase && (bExit || !nCount) ) 815*cdf0e10cSrcweir first = eraseFromList(rActiveEdgeList,first); 816*cdf0e10cSrcweir else 817*cdf0e10cSrcweir ++first; 818*cdf0e10cSrcweir 819*cdf0e10cSrcweir // delayed exit, had to prune first 820*cdf0e10cSrcweir if( bExit ) 821*cdf0e10cSrcweir return; 822*cdf0e10cSrcweir 823*cdf0e10cSrcweir ++nCount; 824*cdf0e10cSrcweir } 825*cdf0e10cSrcweir } 826*cdf0e10cSrcweir 827*cdf0e10cSrcweir template<int bPerformErase> inline void processActiveEdgesTopDown( 828*cdf0e10cSrcweir SweepLineEvent& rCurrEvent, 829*cdf0e10cSrcweir ListOfEdges& rActiveEdgeList, 830*cdf0e10cSrcweir VectorOfPolygons& rPolygonPool, 831*cdf0e10cSrcweir B2DPolyPolygon& rRes ) 832*cdf0e10cSrcweir { 833*cdf0e10cSrcweir processActiveEdges<bPerformErase>( 834*cdf0e10cSrcweir rActiveEdgeList. begin(), 835*cdf0e10cSrcweir rActiveEdgeList. end(), 836*cdf0e10cSrcweir rActiveEdgeList, 837*cdf0e10cSrcweir rCurrEvent, 838*cdf0e10cSrcweir rPolygonPool, 839*cdf0e10cSrcweir rRes); 840*cdf0e10cSrcweir } 841*cdf0e10cSrcweir 842*cdf0e10cSrcweir template<int bPerformErase> inline void processActiveEdgesBottomUp( 843*cdf0e10cSrcweir SweepLineEvent& rCurrEvent, 844*cdf0e10cSrcweir ListOfEdges& rActiveEdgeList, 845*cdf0e10cSrcweir VectorOfPolygons& rPolygonPool, 846*cdf0e10cSrcweir B2DPolyPolygon& rRes ) 847*cdf0e10cSrcweir { 848*cdf0e10cSrcweir processActiveEdges<bPerformErase>( 849*cdf0e10cSrcweir rActiveEdgeList. rbegin(), 850*cdf0e10cSrcweir rActiveEdgeList. rend(), 851*cdf0e10cSrcweir rActiveEdgeList, 852*cdf0e10cSrcweir rCurrEvent, 853*cdf0e10cSrcweir rPolygonPool, 854*cdf0e10cSrcweir rRes); 855*cdf0e10cSrcweir } 856*cdf0e10cSrcweir 857*cdf0e10cSrcweir enum{ NoErase=0, PerformErase=1 }; 858*cdf0e10cSrcweir 859*cdf0e10cSrcweir void handleStartingEdge( SweepLineEvent& rCurrEvent, 860*cdf0e10cSrcweir ListOfEdges& rActiveEdgeList, 861*cdf0e10cSrcweir VectorOfPolygons& rPolygonPool, 862*cdf0e10cSrcweir B2DPolyPolygon& rRes) 863*cdf0e10cSrcweir { 864*cdf0e10cSrcweir // inject two new active edges for rect 865*cdf0e10cSrcweir createActiveEdgesFromStartEvent( rActiveEdgeList, 866*cdf0e10cSrcweir rPolygonPool, 867*cdf0e10cSrcweir rCurrEvent ); 868*cdf0e10cSrcweir 869*cdf0e10cSrcweir if( SweepLineEvent::PROCEED_DOWN == rCurrEvent.getEdgeDirection() ) 870*cdf0e10cSrcweir processActiveEdgesTopDown<NoErase>( 871*cdf0e10cSrcweir rCurrEvent, rActiveEdgeList, rPolygonPool, rRes); 872*cdf0e10cSrcweir else 873*cdf0e10cSrcweir processActiveEdgesBottomUp<NoErase>( 874*cdf0e10cSrcweir rCurrEvent, rActiveEdgeList, rPolygonPool, rRes); 875*cdf0e10cSrcweir } 876*cdf0e10cSrcweir 877*cdf0e10cSrcweir void handleFinishingEdge( SweepLineEvent& rCurrEvent, 878*cdf0e10cSrcweir ListOfEdges& rActiveEdgeList, 879*cdf0e10cSrcweir VectorOfPolygons& rPolygonPool, 880*cdf0e10cSrcweir B2DPolyPolygon& rRes) 881*cdf0e10cSrcweir { 882*cdf0e10cSrcweir if( SweepLineEvent::PROCEED_DOWN == rCurrEvent.getEdgeDirection() ) 883*cdf0e10cSrcweir processActiveEdgesTopDown<PerformErase>( 884*cdf0e10cSrcweir rCurrEvent, rActiveEdgeList, rPolygonPool, rRes); 885*cdf0e10cSrcweir else 886*cdf0e10cSrcweir processActiveEdgesBottomUp<PerformErase>( 887*cdf0e10cSrcweir rCurrEvent, rActiveEdgeList, rPolygonPool, rRes); 888*cdf0e10cSrcweir } 889*cdf0e10cSrcweir 890*cdf0e10cSrcweir inline void handleSweepLineEvent( SweepLineEvent& rCurrEvent, 891*cdf0e10cSrcweir ListOfEdges& rActiveEdgeList, 892*cdf0e10cSrcweir VectorOfPolygons& rPolygonPool, 893*cdf0e10cSrcweir B2DPolyPolygon& rRes) 894*cdf0e10cSrcweir { 895*cdf0e10cSrcweir if( SweepLineEvent::STARTING_EDGE == rCurrEvent.getEdgeType() ) 896*cdf0e10cSrcweir handleStartingEdge(rCurrEvent,rActiveEdgeList,rPolygonPool,rRes); 897*cdf0e10cSrcweir else 898*cdf0e10cSrcweir handleFinishingEdge(rCurrEvent,rActiveEdgeList,rPolygonPool,rRes); 899*cdf0e10cSrcweir } 900*cdf0e10cSrcweir } 901*cdf0e10cSrcweir 902*cdf0e10cSrcweir namespace tools 903*cdf0e10cSrcweir { 904*cdf0e10cSrcweir B2DPolyPolygon solveCrossovers(const std::vector<B2DRange>& rRanges, 905*cdf0e10cSrcweir const std::vector<B2VectorOrientation>& rOrientations) 906*cdf0e10cSrcweir { 907*cdf0e10cSrcweir // sweep-line algorithm to generate a poly-polygon 908*cdf0e10cSrcweir // from a bunch of rectangles 909*cdf0e10cSrcweir // =============================================== 910*cdf0e10cSrcweir // 911*cdf0e10cSrcweir // This algorithm uses the well-known sweep line 912*cdf0e10cSrcweir // concept, explained in every good text book about 913*cdf0e10cSrcweir // computational geometry. 914*cdf0e10cSrcweir // 915*cdf0e10cSrcweir // We start with creating two structures for every 916*cdf0e10cSrcweir // rectangle, one representing the left x coordinate, 917*cdf0e10cSrcweir // one representing the right x coordinate (and both 918*cdf0e10cSrcweir // referencing the original rect). These structs are 919*cdf0e10cSrcweir // sorted with increasing x coordinates. 920*cdf0e10cSrcweir // 921*cdf0e10cSrcweir // Then, we start processing the resulting list from 922*cdf0e10cSrcweir // the beginning. Every entry in the list defines a 923*cdf0e10cSrcweir // point in time of the line sweeping from left to 924*cdf0e10cSrcweir // right across all rectangles. 925*cdf0e10cSrcweir VectorOfEvents aSweepLineEvents; 926*cdf0e10cSrcweir setupSweepLineEventListFromRanges( aSweepLineEvents, 927*cdf0e10cSrcweir rRanges, 928*cdf0e10cSrcweir rOrientations ); 929*cdf0e10cSrcweir 930*cdf0e10cSrcweir B2DPolyPolygon aRes; 931*cdf0e10cSrcweir VectorOfPolygons aPolygonPool; 932*cdf0e10cSrcweir ListOfEdges aActiveEdgeList; 933*cdf0e10cSrcweir 934*cdf0e10cSrcweir // sometimes not enough, but a usable compromise 935*cdf0e10cSrcweir aPolygonPool.reserve( rRanges.size() ); 936*cdf0e10cSrcweir 937*cdf0e10cSrcweir std::for_each( aSweepLineEvents.begin(), 938*cdf0e10cSrcweir aSweepLineEvents.end(), 939*cdf0e10cSrcweir boost::bind( 940*cdf0e10cSrcweir &handleSweepLineEvent, 941*cdf0e10cSrcweir _1, 942*cdf0e10cSrcweir boost::ref(aActiveEdgeList), 943*cdf0e10cSrcweir boost::ref(aPolygonPool), 944*cdf0e10cSrcweir boost::ref(aRes)) ); 945*cdf0e10cSrcweir 946*cdf0e10cSrcweir return aRes; 947*cdf0e10cSrcweir } 948*cdf0e10cSrcweir } 949*cdf0e10cSrcweir } 950*cdf0e10cSrcweir 951