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