xref: /AOO41X/main/basegfx/source/range/b2drangeclipper.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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