1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_basegfx.hxx"
30*cdf0e10cSrcweir #include <osl/diagnose.h>
31*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx>
32*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
33*cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx>
34*cdf0e10cSrcweir #include <basegfx/vector/b2dvector.hxx>
35*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx>
36*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
37*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
38*cdf0e10cSrcweir #include <basegfx/range/b2drange.hxx>
39*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx>
40*cdf0e10cSrcweir #include <basegfx/curve/b2dcubicbezier.hxx>
41*cdf0e10cSrcweir #include <vector>
42*cdf0e10cSrcweir #include <algorithm>
43*cdf0e10cSrcweir 
44*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
45*cdf0e10cSrcweir 
46*cdf0e10cSrcweir namespace basegfx
47*cdf0e10cSrcweir {
48*cdf0e10cSrcweir 	namespace
49*cdf0e10cSrcweir 	{
50*cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////////////
51*cdf0e10cSrcweir 
52*cdf0e10cSrcweir 		struct StripHelper
53*cdf0e10cSrcweir 		{
54*cdf0e10cSrcweir 			B2DRange								maRange;
55*cdf0e10cSrcweir 			sal_Int32								mnDepth;
56*cdf0e10cSrcweir 			B2VectorOrientation						meOrinetation;
57*cdf0e10cSrcweir 		};
58*cdf0e10cSrcweir 
59*cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////////////
60*cdf0e10cSrcweir 
61*cdf0e10cSrcweir 		struct PN
62*cdf0e10cSrcweir         {
63*cdf0e10cSrcweir         public:
64*cdf0e10cSrcweir             B2DPoint                maPoint;
65*cdf0e10cSrcweir             sal_uInt32              mnI;
66*cdf0e10cSrcweir             sal_uInt32              mnIP;
67*cdf0e10cSrcweir             sal_uInt32              mnIN;
68*cdf0e10cSrcweir         };
69*cdf0e10cSrcweir 
70*cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////////////
71*cdf0e10cSrcweir 
72*cdf0e10cSrcweir 		struct VN
73*cdf0e10cSrcweir         {
74*cdf0e10cSrcweir         public:
75*cdf0e10cSrcweir             B2DVector               maPrev;
76*cdf0e10cSrcweir             B2DVector               maNext;
77*cdf0e10cSrcweir 
78*cdf0e10cSrcweir 			// to have the correct curve segments in the crossover checks,
79*cdf0e10cSrcweir 			// it is necessary to keep the original next vectors, too. Else,
80*cdf0e10cSrcweir 			// it may happen to use a already switched next vector which
81*cdf0e10cSrcweir 			// would interpolate the wrong comparison point
82*cdf0e10cSrcweir             B2DVector               maOriginalNext;
83*cdf0e10cSrcweir         };
84*cdf0e10cSrcweir 
85*cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////////////
86*cdf0e10cSrcweir 
87*cdf0e10cSrcweir 		struct SN
88*cdf0e10cSrcweir         {
89*cdf0e10cSrcweir         public:
90*cdf0e10cSrcweir             PN*                     mpPN;
91*cdf0e10cSrcweir 
92*cdf0e10cSrcweir             bool operator<(const SN& rComp) const
93*cdf0e10cSrcweir 			{
94*cdf0e10cSrcweir 				if(fTools::equal(mpPN->maPoint.getX(), rComp.mpPN->maPoint.getX()))
95*cdf0e10cSrcweir 				{
96*cdf0e10cSrcweir 					if(fTools::equal(mpPN->maPoint.getY(), rComp.mpPN->maPoint.getY()))
97*cdf0e10cSrcweir 					{
98*cdf0e10cSrcweir 						return (mpPN->mnI < rComp.mpPN->mnI);
99*cdf0e10cSrcweir 					}
100*cdf0e10cSrcweir 					else
101*cdf0e10cSrcweir 					{
102*cdf0e10cSrcweir 						return fTools::less(mpPN->maPoint.getY(), rComp.mpPN->maPoint.getY());
103*cdf0e10cSrcweir 					}
104*cdf0e10cSrcweir 				}
105*cdf0e10cSrcweir 				else
106*cdf0e10cSrcweir 				{
107*cdf0e10cSrcweir 					return fTools::less(mpPN->maPoint.getX(), rComp.mpPN->maPoint.getX());
108*cdf0e10cSrcweir 				}
109*cdf0e10cSrcweir 			}
110*cdf0e10cSrcweir         };
111*cdf0e10cSrcweir 
112*cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////////////
113*cdf0e10cSrcweir 
114*cdf0e10cSrcweir 		typedef ::std::vector< PN > PNV;
115*cdf0e10cSrcweir 		typedef ::std::vector< VN > VNV;
116*cdf0e10cSrcweir 		typedef ::std::vector< SN > SNV;
117*cdf0e10cSrcweir 
118*cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////////////
119*cdf0e10cSrcweir 
120*cdf0e10cSrcweir 		class solver
121*cdf0e10cSrcweir         {
122*cdf0e10cSrcweir         private:
123*cdf0e10cSrcweir             const B2DPolyPolygon    maOriginal;
124*cdf0e10cSrcweir             PNV                     maPNV;
125*cdf0e10cSrcweir             VNV                     maVNV;
126*cdf0e10cSrcweir             SNV                     maSNV;
127*cdf0e10cSrcweir 
128*cdf0e10cSrcweir             unsigned                mbIsCurve : 1;
129*cdf0e10cSrcweir             unsigned                mbChanged : 1;
130*cdf0e10cSrcweir 
131*cdf0e10cSrcweir             void impAddPolygon(const sal_uInt32 aPos, const B2DPolygon& rGeometry)
132*cdf0e10cSrcweir             {
133*cdf0e10cSrcweir                 const sal_uInt32 nCount(rGeometry.count());
134*cdf0e10cSrcweir                 PN aNewPN;
135*cdf0e10cSrcweir                 VN aNewVN;
136*cdf0e10cSrcweir                 SN aNewSN;
137*cdf0e10cSrcweir 
138*cdf0e10cSrcweir                 for(sal_uInt32 a(0); a < nCount; a++)
139*cdf0e10cSrcweir 	            {
140*cdf0e10cSrcweir                     const B2DPoint aPoint(rGeometry.getB2DPoint(a));
141*cdf0e10cSrcweir                     aNewPN.maPoint = aPoint;
142*cdf0e10cSrcweir                     aNewPN.mnI = aPos + a;
143*cdf0e10cSrcweir 		            aNewPN.mnIP = aPos + ((a != 0) ? a - 1 : nCount - 1);
144*cdf0e10cSrcweir 		            aNewPN.mnIN = aPos + ((a + 1 == nCount) ? 0 : a + 1);
145*cdf0e10cSrcweir                     maPNV.push_back(aNewPN);
146*cdf0e10cSrcweir 
147*cdf0e10cSrcweir                     if(mbIsCurve)
148*cdf0e10cSrcweir                     {
149*cdf0e10cSrcweir                         aNewVN.maPrev = rGeometry.getPrevControlPoint(a) - aPoint;
150*cdf0e10cSrcweir                         aNewVN.maNext = rGeometry.getNextControlPoint(a) - aPoint;
151*cdf0e10cSrcweir 						aNewVN.maOriginalNext = aNewVN.maNext;
152*cdf0e10cSrcweir                         maVNV.push_back(aNewVN);
153*cdf0e10cSrcweir                     }
154*cdf0e10cSrcweir 
155*cdf0e10cSrcweir                     aNewSN.mpPN = &maPNV[maPNV.size() - 1];
156*cdf0e10cSrcweir                     maSNV.push_back(aNewSN);
157*cdf0e10cSrcweir                 }
158*cdf0e10cSrcweir             }
159*cdf0e10cSrcweir 
160*cdf0e10cSrcweir 			bool impLeftOfEdges(const B2DVector& rVecA, const B2DVector& rVecB, const B2DVector& rTest)
161*cdf0e10cSrcweir 			{
162*cdf0e10cSrcweir 				// tests if rTest is left of both directed line segments along the line -rVecA, rVecB. Test is
163*cdf0e10cSrcweir 				// with border.
164*cdf0e10cSrcweir 				if(rVecA.cross(rVecB) > 0.0)
165*cdf0e10cSrcweir 				{
166*cdf0e10cSrcweir 					// b is left turn seen from a, test if Test is left of both and so inside (left is seeen as inside)
167*cdf0e10cSrcweir 					const bool bBoolA(fTools::moreOrEqual(rVecA.cross(rTest), 0.0));
168*cdf0e10cSrcweir 					const bool bBoolB(fTools::lessOrEqual(rVecB.cross(rTest), 0.0));
169*cdf0e10cSrcweir 
170*cdf0e10cSrcweir 					return (bBoolA && bBoolB);
171*cdf0e10cSrcweir 				}
172*cdf0e10cSrcweir 				else
173*cdf0e10cSrcweir 				{
174*cdf0e10cSrcweir 					// b is right turn seen from a, test if Test is right of both and so outside (left is seeen as inside)
175*cdf0e10cSrcweir 					const bool bBoolA(fTools::lessOrEqual(rVecA.cross(rTest), 0.0));
176*cdf0e10cSrcweir 					const bool bBoolB(fTools::moreOrEqual(rVecB.cross(rTest), 0.0));
177*cdf0e10cSrcweir 
178*cdf0e10cSrcweir 					return (!(bBoolA && bBoolB));
179*cdf0e10cSrcweir 				}
180*cdf0e10cSrcweir 			}
181*cdf0e10cSrcweir 
182*cdf0e10cSrcweir 			void impSwitchNext(PN& rPNa, PN& rPNb)
183*cdf0e10cSrcweir 			{
184*cdf0e10cSrcweir 				::std::swap(rPNa.mnIN, rPNb.mnIN);
185*cdf0e10cSrcweir 
186*cdf0e10cSrcweir 				if(mbIsCurve)
187*cdf0e10cSrcweir 				{
188*cdf0e10cSrcweir 					VN& rVNa = maVNV[rPNa.mnI];
189*cdf0e10cSrcweir 					VN& rVNb = maVNV[rPNb.mnI];
190*cdf0e10cSrcweir 
191*cdf0e10cSrcweir 					::std::swap(rVNa.maNext, rVNb.maNext);
192*cdf0e10cSrcweir 				}
193*cdf0e10cSrcweir 
194*cdf0e10cSrcweir 				if(!mbChanged)
195*cdf0e10cSrcweir 				{
196*cdf0e10cSrcweir 					mbChanged = true;
197*cdf0e10cSrcweir 				}
198*cdf0e10cSrcweir 			}
199*cdf0e10cSrcweir 
200*cdf0e10cSrcweir             B2DCubicBezier createSegment(const PN& rPN, bool bPrev) const
201*cdf0e10cSrcweir             {
202*cdf0e10cSrcweir                 const B2DPoint& rStart(rPN.maPoint);
203*cdf0e10cSrcweir                 const B2DPoint& rEnd(maPNV[bPrev ? rPN.mnIP : rPN.mnIN].maPoint);
204*cdf0e10cSrcweir                 const B2DVector& rCPA(bPrev ? maVNV[rPN.mnI].maPrev : maVNV[rPN.mnI].maNext);
205*cdf0e10cSrcweir 				// Use maOriginalNext, not maNext to create the original (yet unchanged)
206*cdf0e10cSrcweir 				// curve segment. Otherwise, this segment would NOT ne correct.
207*cdf0e10cSrcweir                 const B2DVector& rCPB(bPrev ? maVNV[maPNV[rPN.mnIP].mnI].maOriginalNext : maVNV[maPNV[rPN.mnIN].mnI].maPrev);
208*cdf0e10cSrcweir 
209*cdf0e10cSrcweir                 return B2DCubicBezier(rStart, rStart + rCPA, rEnd + rCPB, rEnd);
210*cdf0e10cSrcweir             }
211*cdf0e10cSrcweir 
212*cdf0e10cSrcweir 			void impHandleCommon(PN& rPNa, PN& rPNb)
213*cdf0e10cSrcweir             {
214*cdf0e10cSrcweir                 if(mbIsCurve)
215*cdf0e10cSrcweir                 {
216*cdf0e10cSrcweir                     const B2DCubicBezier aNextA(createSegment(rPNa, false));
217*cdf0e10cSrcweir                     const B2DCubicBezier aPrevA(createSegment(rPNa, true));
218*cdf0e10cSrcweir 
219*cdf0e10cSrcweir                     if(aNextA.equal(aPrevA))
220*cdf0e10cSrcweir                     {
221*cdf0e10cSrcweir                         // deadend on A (identical edge)
222*cdf0e10cSrcweir                         return;
223*cdf0e10cSrcweir                     }
224*cdf0e10cSrcweir 
225*cdf0e10cSrcweir                     const B2DCubicBezier aNextB(createSegment(rPNb, false));
226*cdf0e10cSrcweir                     const B2DCubicBezier aPrevB(createSegment(rPNb, true));
227*cdf0e10cSrcweir 
228*cdf0e10cSrcweir                     if(aNextB.equal(aPrevB))
229*cdf0e10cSrcweir                     {
230*cdf0e10cSrcweir                         // deadend on B (identical edge)
231*cdf0e10cSrcweir                         return;
232*cdf0e10cSrcweir                     }
233*cdf0e10cSrcweir 
234*cdf0e10cSrcweir                     if(aPrevA.equal(aPrevB))
235*cdf0e10cSrcweir                     {
236*cdf0e10cSrcweir                         // common edge in same direction
237*cdf0e10cSrcweir                         if(aNextA.equal(aNextB))
238*cdf0e10cSrcweir                         {
239*cdf0e10cSrcweir                             // common edge in same direction continues
240*cdf0e10cSrcweir                             return;
241*cdf0e10cSrcweir                         }
242*cdf0e10cSrcweir                         else
243*cdf0e10cSrcweir                         {
244*cdf0e10cSrcweir                             // common edge in same direction leave
245*cdf0e10cSrcweir                             // action is done on enter
246*cdf0e10cSrcweir                             return;
247*cdf0e10cSrcweir                         }
248*cdf0e10cSrcweir                     }
249*cdf0e10cSrcweir                     else if(aPrevA.equal(aNextB))
250*cdf0e10cSrcweir                     {
251*cdf0e10cSrcweir                         // common edge in opposite direction
252*cdf0e10cSrcweir                         if(aNextA.equal(aPrevB))
253*cdf0e10cSrcweir                         {
254*cdf0e10cSrcweir                             // common edge in opposite direction continues
255*cdf0e10cSrcweir                             return;
256*cdf0e10cSrcweir                         }
257*cdf0e10cSrcweir                         else
258*cdf0e10cSrcweir                         {
259*cdf0e10cSrcweir                             // common edge in opposite direction leave
260*cdf0e10cSrcweir                             impSwitchNext(rPNa, rPNb);
261*cdf0e10cSrcweir                         }
262*cdf0e10cSrcweir                     }
263*cdf0e10cSrcweir                     else if(aNextA.equal(aNextB))
264*cdf0e10cSrcweir                     {
265*cdf0e10cSrcweir                         // common edge in same direction enter
266*cdf0e10cSrcweir                         // search leave edge
267*cdf0e10cSrcweir                         PN* pPNa2 = &maPNV[rPNa.mnIN];
268*cdf0e10cSrcweir                         PN* pPNb2 = &maPNV[rPNb.mnIN];
269*cdf0e10cSrcweir                         bool bOnEdge(true);
270*cdf0e10cSrcweir 
271*cdf0e10cSrcweir                         do
272*cdf0e10cSrcweir                         {
273*cdf0e10cSrcweir                             const B2DCubicBezier aNextA2(createSegment(*pPNa2, false));
274*cdf0e10cSrcweir                             const B2DCubicBezier aNextB2(createSegment(*pPNb2, false));
275*cdf0e10cSrcweir 
276*cdf0e10cSrcweir                             if(aNextA2.equal(aNextB2))
277*cdf0e10cSrcweir                             {
278*cdf0e10cSrcweir                                 pPNa2 = &maPNV[pPNa2->mnIN];
279*cdf0e10cSrcweir                                 pPNb2 = &maPNV[pPNb2->mnIN];
280*cdf0e10cSrcweir                             }
281*cdf0e10cSrcweir                             else
282*cdf0e10cSrcweir                             {
283*cdf0e10cSrcweir                                 bOnEdge = false;
284*cdf0e10cSrcweir                             }
285*cdf0e10cSrcweir                         }
286*cdf0e10cSrcweir                         while(bOnEdge && pPNa2 != &rPNa && pPNa2 != &rPNa);
287*cdf0e10cSrcweir 
288*cdf0e10cSrcweir                         if(bOnEdge)
289*cdf0e10cSrcweir                         {
290*cdf0e10cSrcweir                             // loop over two identical polygon paths
291*cdf0e10cSrcweir                             return;
292*cdf0e10cSrcweir                         }
293*cdf0e10cSrcweir                         else
294*cdf0e10cSrcweir                         {
295*cdf0e10cSrcweir                             // enter at rPNa, rPNb; leave at pPNa2, pPNb2. No common edges
296*cdf0e10cSrcweir                             // at enter/leave. Check for crossover.
297*cdf0e10cSrcweir                             const B2DVector aPrevCA(aPrevA.interpolatePoint(0.5) - aPrevA.getStartPoint());
298*cdf0e10cSrcweir                             const B2DVector aNextCA(aNextA.interpolatePoint(0.5) - aNextA.getStartPoint());
299*cdf0e10cSrcweir                             const B2DVector aPrevCB(aPrevB.interpolatePoint(0.5) - aPrevB.getStartPoint());
300*cdf0e10cSrcweir                             const bool bEnter(impLeftOfEdges(aPrevCA, aNextCA, aPrevCB));
301*cdf0e10cSrcweir 
302*cdf0e10cSrcweir                             const B2DCubicBezier aNextA2(createSegment(*pPNa2, false));
303*cdf0e10cSrcweir                             const B2DCubicBezier aPrevA2(createSegment(*pPNa2, true));
304*cdf0e10cSrcweir                             const B2DCubicBezier aNextB2(createSegment(*pPNb2, false));
305*cdf0e10cSrcweir                             const B2DVector aPrevCA2(aPrevA2.interpolatePoint(0.5) - aPrevA2.getStartPoint());
306*cdf0e10cSrcweir                             const B2DVector aNextCA2(aNextA2.interpolatePoint(0.5) - aNextA2.getStartPoint());
307*cdf0e10cSrcweir                             const B2DVector aNextCB2(aNextB2.interpolatePoint(0.5) - aNextB2.getStartPoint());
308*cdf0e10cSrcweir                             const bool bLeave(impLeftOfEdges(aPrevCA2, aNextCA2, aNextCB2));
309*cdf0e10cSrcweir 
310*cdf0e10cSrcweir                             if(bEnter != bLeave)
311*cdf0e10cSrcweir                             {
312*cdf0e10cSrcweir                                 // crossover
313*cdf0e10cSrcweir                                 impSwitchNext(rPNa, rPNb);
314*cdf0e10cSrcweir                             }
315*cdf0e10cSrcweir                         }
316*cdf0e10cSrcweir                     }
317*cdf0e10cSrcweir                     else if(aNextA.equal(aPrevB))
318*cdf0e10cSrcweir                     {
319*cdf0e10cSrcweir                         // common edge in opposite direction enter
320*cdf0e10cSrcweir                         impSwitchNext(rPNa, rPNb);
321*cdf0e10cSrcweir                     }
322*cdf0e10cSrcweir                     else
323*cdf0e10cSrcweir                     {
324*cdf0e10cSrcweir                         // no common edges, check for crossover
325*cdf0e10cSrcweir                         const B2DVector aPrevCA(aPrevA.interpolatePoint(0.5) - aPrevA.getStartPoint());
326*cdf0e10cSrcweir                         const B2DVector aNextCA(aNextA.interpolatePoint(0.5) - aNextA.getStartPoint());
327*cdf0e10cSrcweir                         const B2DVector aPrevCB(aPrevB.interpolatePoint(0.5) - aPrevB.getStartPoint());
328*cdf0e10cSrcweir                         const B2DVector aNextCB(aNextB.interpolatePoint(0.5) - aNextB.getStartPoint());
329*cdf0e10cSrcweir 
330*cdf0e10cSrcweir                         const bool bEnter(impLeftOfEdges(aPrevCA, aNextCA, aPrevCB));
331*cdf0e10cSrcweir                         const bool bLeave(impLeftOfEdges(aPrevCA, aNextCA, aNextCB));
332*cdf0e10cSrcweir 
333*cdf0e10cSrcweir                         if(bEnter != bLeave)
334*cdf0e10cSrcweir                         {
335*cdf0e10cSrcweir                             // crossover
336*cdf0e10cSrcweir                             impSwitchNext(rPNa, rPNb);
337*cdf0e10cSrcweir                         }
338*cdf0e10cSrcweir                     }
339*cdf0e10cSrcweir                 }
340*cdf0e10cSrcweir                 else
341*cdf0e10cSrcweir                 {
342*cdf0e10cSrcweir                     const B2DPoint& rNextA(maPNV[rPNa.mnIN].maPoint);
343*cdf0e10cSrcweir                     const B2DPoint& rPrevA(maPNV[rPNa.mnIP].maPoint);
344*cdf0e10cSrcweir 
345*cdf0e10cSrcweir                     if(rNextA.equal(rPrevA))
346*cdf0e10cSrcweir                     {
347*cdf0e10cSrcweir                         // deadend on A
348*cdf0e10cSrcweir                         return;
349*cdf0e10cSrcweir                     }
350*cdf0e10cSrcweir 
351*cdf0e10cSrcweir                     const B2DPoint& rNextB(maPNV[rPNb.mnIN].maPoint);
352*cdf0e10cSrcweir                     const B2DPoint& rPrevB(maPNV[rPNb.mnIP].maPoint);
353*cdf0e10cSrcweir 
354*cdf0e10cSrcweir                     if(rNextB.equal(rPrevB))
355*cdf0e10cSrcweir                     {
356*cdf0e10cSrcweir                         // deadend on B
357*cdf0e10cSrcweir                         return;
358*cdf0e10cSrcweir                     }
359*cdf0e10cSrcweir 
360*cdf0e10cSrcweir                     if(rPrevA.equal(rPrevB))
361*cdf0e10cSrcweir                     {
362*cdf0e10cSrcweir                         // common edge in same direction
363*cdf0e10cSrcweir                         if(rNextA.equal(rNextB))
364*cdf0e10cSrcweir                         {
365*cdf0e10cSrcweir                             // common edge in same direction continues
366*cdf0e10cSrcweir                             return;
367*cdf0e10cSrcweir                         }
368*cdf0e10cSrcweir                         else
369*cdf0e10cSrcweir                         {
370*cdf0e10cSrcweir                             // common edge in same direction leave
371*cdf0e10cSrcweir                             // action is done on enter
372*cdf0e10cSrcweir                             return;
373*cdf0e10cSrcweir                         }
374*cdf0e10cSrcweir                     }
375*cdf0e10cSrcweir                     else if(rPrevA.equal(rNextB))
376*cdf0e10cSrcweir                     {
377*cdf0e10cSrcweir                         // common edge in opposite direction
378*cdf0e10cSrcweir                         if(rNextA.equal(rPrevB))
379*cdf0e10cSrcweir                         {
380*cdf0e10cSrcweir                             // common edge in opposite direction continues
381*cdf0e10cSrcweir                             return;
382*cdf0e10cSrcweir                         }
383*cdf0e10cSrcweir                         else
384*cdf0e10cSrcweir                         {
385*cdf0e10cSrcweir                             // common edge in opposite direction leave
386*cdf0e10cSrcweir                             impSwitchNext(rPNa, rPNb);
387*cdf0e10cSrcweir                         }
388*cdf0e10cSrcweir                     }
389*cdf0e10cSrcweir                     else if(rNextA.equal(rNextB))
390*cdf0e10cSrcweir                     {
391*cdf0e10cSrcweir                         // common edge in same direction enter
392*cdf0e10cSrcweir                         // search leave edge
393*cdf0e10cSrcweir                         PN* pPNa2 = &maPNV[rPNa.mnIN];
394*cdf0e10cSrcweir                         PN* pPNb2 = &maPNV[rPNb.mnIN];
395*cdf0e10cSrcweir                         bool bOnEdge(true);
396*cdf0e10cSrcweir 
397*cdf0e10cSrcweir                         do
398*cdf0e10cSrcweir                         {
399*cdf0e10cSrcweir                             const B2DPoint& rNextA2(maPNV[pPNa2->mnIN].maPoint);
400*cdf0e10cSrcweir                             const B2DPoint& rNextB2(maPNV[pPNb2->mnIN].maPoint);
401*cdf0e10cSrcweir 
402*cdf0e10cSrcweir                             if(rNextA2.equal(rNextB2))
403*cdf0e10cSrcweir                             {
404*cdf0e10cSrcweir                                 pPNa2 = &maPNV[pPNa2->mnIN];
405*cdf0e10cSrcweir                                 pPNb2 = &maPNV[pPNb2->mnIN];
406*cdf0e10cSrcweir                             }
407*cdf0e10cSrcweir                             else
408*cdf0e10cSrcweir                             {
409*cdf0e10cSrcweir                                 bOnEdge = false;
410*cdf0e10cSrcweir                             }
411*cdf0e10cSrcweir                         }
412*cdf0e10cSrcweir                         while(bOnEdge && pPNa2 != &rPNa && pPNa2 != &rPNa);
413*cdf0e10cSrcweir 
414*cdf0e10cSrcweir                         if(bOnEdge)
415*cdf0e10cSrcweir                         {
416*cdf0e10cSrcweir                             // loop over two identical polygon paths
417*cdf0e10cSrcweir                             return;
418*cdf0e10cSrcweir                         }
419*cdf0e10cSrcweir                         else
420*cdf0e10cSrcweir                         {
421*cdf0e10cSrcweir                             // enter at rPNa, rPNb; leave at pPNa2, pPNb2. No common edges
422*cdf0e10cSrcweir                             // at enter/leave. Check for crossover.
423*cdf0e10cSrcweir                             const B2DPoint& aPointE(rPNa.maPoint);
424*cdf0e10cSrcweir                             const B2DVector aPrevAE(rPrevA - aPointE);
425*cdf0e10cSrcweir                             const B2DVector aNextAE(rNextA - aPointE);
426*cdf0e10cSrcweir                             const B2DVector aPrevBE(rPrevB - aPointE);
427*cdf0e10cSrcweir 
428*cdf0e10cSrcweir                             const B2DPoint& aPointL(pPNa2->maPoint);
429*cdf0e10cSrcweir                             const B2DVector aPrevAL(maPNV[pPNa2->mnIP].maPoint - aPointL);
430*cdf0e10cSrcweir                             const B2DVector aNextAL(maPNV[pPNa2->mnIN].maPoint - aPointL);
431*cdf0e10cSrcweir                             const B2DVector aNextBL(maPNV[pPNb2->mnIN].maPoint - aPointL);
432*cdf0e10cSrcweir 
433*cdf0e10cSrcweir                             const bool bEnter(impLeftOfEdges(aPrevAE, aNextAE, aPrevBE));
434*cdf0e10cSrcweir                             const bool bLeave(impLeftOfEdges(aPrevAL, aNextAL, aNextBL));
435*cdf0e10cSrcweir 
436*cdf0e10cSrcweir                             if(bEnter != bLeave)
437*cdf0e10cSrcweir                             {
438*cdf0e10cSrcweir                                 // crossover; switch start or end
439*cdf0e10cSrcweir                                 impSwitchNext(rPNa, rPNb);
440*cdf0e10cSrcweir                             }
441*cdf0e10cSrcweir                         }
442*cdf0e10cSrcweir                     }
443*cdf0e10cSrcweir                     else if(rNextA.equal(rPrevB))
444*cdf0e10cSrcweir                     {
445*cdf0e10cSrcweir                         // common edge in opposite direction enter
446*cdf0e10cSrcweir                         impSwitchNext(rPNa, rPNb);
447*cdf0e10cSrcweir                     }
448*cdf0e10cSrcweir                     else
449*cdf0e10cSrcweir                     {
450*cdf0e10cSrcweir                         // no common edges, check for crossover
451*cdf0e10cSrcweir                         const B2DPoint& aPoint(rPNa.maPoint);
452*cdf0e10cSrcweir                         const B2DVector aPrevA(rPrevA - aPoint);
453*cdf0e10cSrcweir                         const B2DVector aNextA(rNextA - aPoint);
454*cdf0e10cSrcweir                         const B2DVector aPrevB(rPrevB - aPoint);
455*cdf0e10cSrcweir                         const B2DVector aNextB(rNextB - aPoint);
456*cdf0e10cSrcweir 
457*cdf0e10cSrcweir                         const bool bEnter(impLeftOfEdges(aPrevA, aNextA, aPrevB));
458*cdf0e10cSrcweir                         const bool bLeave(impLeftOfEdges(aPrevA, aNextA, aNextB));
459*cdf0e10cSrcweir 
460*cdf0e10cSrcweir                         if(bEnter != bLeave)
461*cdf0e10cSrcweir                         {
462*cdf0e10cSrcweir                             // crossover
463*cdf0e10cSrcweir                             impSwitchNext(rPNa, rPNb);
464*cdf0e10cSrcweir                         }
465*cdf0e10cSrcweir                     }
466*cdf0e10cSrcweir                 }
467*cdf0e10cSrcweir             }
468*cdf0e10cSrcweir 
469*cdf0e10cSrcweir 			void impSolve()
470*cdf0e10cSrcweir 			{
471*cdf0e10cSrcweir 		        // sort by point to identify common nodes
472*cdf0e10cSrcweir 		        ::std::sort(maSNV.begin(), maSNV.end());
473*cdf0e10cSrcweir 
474*cdf0e10cSrcweir 		        // handle common nodes
475*cdf0e10cSrcweir 				const sal_uInt32 nNodeCount(maSNV.size());
476*cdf0e10cSrcweir 
477*cdf0e10cSrcweir 		        for(sal_uInt32 a(0); a < nNodeCount - 1; a++)
478*cdf0e10cSrcweir 		        {
479*cdf0e10cSrcweir 			        // test a before using it, not after. Also use nPointCount instead of aSortNodes.size()
480*cdf0e10cSrcweir                     PN& rPNb = *(maSNV[a].mpPN);
481*cdf0e10cSrcweir 
482*cdf0e10cSrcweir 			        for(sal_uInt32 b(a + 1); b < nNodeCount && rPNb.maPoint.equal(maSNV[b].mpPN->maPoint); b++)
483*cdf0e10cSrcweir 			        {
484*cdf0e10cSrcweir 				        impHandleCommon(rPNb, *maSNV[b].mpPN);
485*cdf0e10cSrcweir 			        }
486*cdf0e10cSrcweir 		        }
487*cdf0e10cSrcweir 			}
488*cdf0e10cSrcweir 
489*cdf0e10cSrcweir 		public:
490*cdf0e10cSrcweir             solver(const B2DPolygon& rOriginal)
491*cdf0e10cSrcweir             :   maOriginal(B2DPolyPolygon(rOriginal)),
492*cdf0e10cSrcweir                 mbIsCurve(false),
493*cdf0e10cSrcweir                 mbChanged(false)
494*cdf0e10cSrcweir             {
495*cdf0e10cSrcweir                 const sal_uInt32 nOriginalCount(rOriginal.count());
496*cdf0e10cSrcweir 
497*cdf0e10cSrcweir                 if(nOriginalCount)
498*cdf0e10cSrcweir                 {
499*cdf0e10cSrcweir 				    B2DPolygon aGeometry(tools::addPointsAtCutsAndTouches(rOriginal));
500*cdf0e10cSrcweir 				    aGeometry.removeDoublePoints();
501*cdf0e10cSrcweir                     aGeometry = tools::simplifyCurveSegments(aGeometry);
502*cdf0e10cSrcweir                     mbIsCurve = aGeometry.areControlPointsUsed();
503*cdf0e10cSrcweir 
504*cdf0e10cSrcweir                     const sal_uInt32 nPointCount(aGeometry.count());
505*cdf0e10cSrcweir 
506*cdf0e10cSrcweir                     // If it's not a pezier polygon, at least four points are needed to create
507*cdf0e10cSrcweir                     // a self-intersection. If it's a bezier polygon, the minimum point number
508*cdf0e10cSrcweir                     // is two, since with a single point You get a curve, but no self-intersection
509*cdf0e10cSrcweir                     if(nPointCount > 3 || (nPointCount > 1 && mbIsCurve))
510*cdf0e10cSrcweir                     {
511*cdf0e10cSrcweir 				        // reserve space in point, control and sort vector.
512*cdf0e10cSrcweir                         maSNV.reserve(nPointCount);
513*cdf0e10cSrcweir 				        maPNV.reserve(nPointCount);
514*cdf0e10cSrcweir                         maVNV.reserve(mbIsCurve ? nPointCount : 0);
515*cdf0e10cSrcweir 
516*cdf0e10cSrcweir 				        // fill data
517*cdf0e10cSrcweir                         impAddPolygon(0, aGeometry);
518*cdf0e10cSrcweir 
519*cdf0e10cSrcweir 						// solve common nodes
520*cdf0e10cSrcweir 						impSolve();
521*cdf0e10cSrcweir                     }
522*cdf0e10cSrcweir                 }
523*cdf0e10cSrcweir             }
524*cdf0e10cSrcweir 
525*cdf0e10cSrcweir 			solver(const B2DPolyPolygon& rOriginal)
526*cdf0e10cSrcweir             :   maOriginal(rOriginal),
527*cdf0e10cSrcweir                 mbIsCurve(false),
528*cdf0e10cSrcweir                 mbChanged(false)
529*cdf0e10cSrcweir             {
530*cdf0e10cSrcweir                 sal_uInt32 nOriginalCount(maOriginal.count());
531*cdf0e10cSrcweir 
532*cdf0e10cSrcweir                 if(nOriginalCount)
533*cdf0e10cSrcweir                 {
534*cdf0e10cSrcweir 				    B2DPolyPolygon aGeometry(tools::addPointsAtCutsAndTouches(maOriginal, true));
535*cdf0e10cSrcweir 					aGeometry.removeDoublePoints();
536*cdf0e10cSrcweir                     aGeometry = tools::simplifyCurveSegments(aGeometry);
537*cdf0e10cSrcweir                     mbIsCurve = aGeometry.areControlPointsUsed();
538*cdf0e10cSrcweir 					nOriginalCount = aGeometry.count();
539*cdf0e10cSrcweir 
540*cdf0e10cSrcweir 					if(nOriginalCount)
541*cdf0e10cSrcweir 					{
542*cdf0e10cSrcweir 						sal_uInt32 nPointCount(0);
543*cdf0e10cSrcweir 						sal_uInt32 a(0);
544*cdf0e10cSrcweir 
545*cdf0e10cSrcweir 						// count points
546*cdf0e10cSrcweir 						for(a = 0; a < nOriginalCount; a++)
547*cdf0e10cSrcweir 						{
548*cdf0e10cSrcweir 							const B2DPolygon aCandidate(aGeometry.getB2DPolygon(a));
549*cdf0e10cSrcweir 							const sal_uInt32 nCandCount(aCandidate.count());
550*cdf0e10cSrcweir 
551*cdf0e10cSrcweir                             // If it's not a bezier curve, at least three points would be needed to have a
552*cdf0e10cSrcweir                             // topological relevant (not empty) polygon. Since its not known here if trivial
553*cdf0e10cSrcweir                             // edges (dead ends) will be kept or sorted out, add non-bezier polygons with
554*cdf0e10cSrcweir                             // more than one point.
555*cdf0e10cSrcweir                             // For bezier curves, the minimum for defining an area is also one.
556*cdf0e10cSrcweir 							if(nCandCount)
557*cdf0e10cSrcweir 							{
558*cdf0e10cSrcweir 								nPointCount += nCandCount;
559*cdf0e10cSrcweir 							}
560*cdf0e10cSrcweir 						}
561*cdf0e10cSrcweir 
562*cdf0e10cSrcweir                         if(nPointCount)
563*cdf0e10cSrcweir                         {
564*cdf0e10cSrcweir 				            // reserve space in point, control and sort vector.
565*cdf0e10cSrcweir                             maSNV.reserve(nPointCount);
566*cdf0e10cSrcweir 				            maPNV.reserve(nPointCount);
567*cdf0e10cSrcweir                             maVNV.reserve(mbIsCurve ? nPointCount : 0);
568*cdf0e10cSrcweir 
569*cdf0e10cSrcweir 				            // fill data
570*cdf0e10cSrcweir 	                        sal_uInt32 nInsertIndex(0);
571*cdf0e10cSrcweir 
572*cdf0e10cSrcweir 						    for(a = 0; a < nOriginalCount; a++)
573*cdf0e10cSrcweir 						    {
574*cdf0e10cSrcweir 							    const B2DPolygon aCandidate(aGeometry.getB2DPolygon(a));
575*cdf0e10cSrcweir 							    const sal_uInt32 nCandCount(aCandidate.count());
576*cdf0e10cSrcweir 
577*cdf0e10cSrcweir                                 // use same condition as above, the data vector is
578*cdf0e10cSrcweir                                 // pre-allocated
579*cdf0e10cSrcweir 							    if(nCandCount)
580*cdf0e10cSrcweir 							    {
581*cdf0e10cSrcweir 		                            impAddPolygon(nInsertIndex, aCandidate);
582*cdf0e10cSrcweir 								    nInsertIndex += nCandCount;
583*cdf0e10cSrcweir 							    }
584*cdf0e10cSrcweir 						    }
585*cdf0e10cSrcweir 
586*cdf0e10cSrcweir 						    // solve common nodes
587*cdf0e10cSrcweir 						    impSolve();
588*cdf0e10cSrcweir                         }
589*cdf0e10cSrcweir 					}
590*cdf0e10cSrcweir                 }
591*cdf0e10cSrcweir             }
592*cdf0e10cSrcweir 
593*cdf0e10cSrcweir 			B2DPolyPolygon getB2DPolyPolygon()
594*cdf0e10cSrcweir 			{
595*cdf0e10cSrcweir 				if(mbChanged)
596*cdf0e10cSrcweir 				{
597*cdf0e10cSrcweir 					B2DPolyPolygon aRetval;
598*cdf0e10cSrcweir 					const sal_uInt32 nCount(maPNV.size());
599*cdf0e10cSrcweir 					sal_uInt32 nCountdown(nCount);
600*cdf0e10cSrcweir 
601*cdf0e10cSrcweir 					for(sal_uInt32 a(0); nCountdown && a < nCount; a++)
602*cdf0e10cSrcweir 					{
603*cdf0e10cSrcweir                         PN& rPN = maPNV[a];
604*cdf0e10cSrcweir 
605*cdf0e10cSrcweir 						if(SAL_MAX_UINT32 != rPN.mnI)
606*cdf0e10cSrcweir 						{
607*cdf0e10cSrcweir 							// unused node, start new part polygon
608*cdf0e10cSrcweir 							B2DPolygon aNewPart;
609*cdf0e10cSrcweir 	                        PN* pPNCurr = &rPN;
610*cdf0e10cSrcweir 
611*cdf0e10cSrcweir 							do
612*cdf0e10cSrcweir 							{
613*cdf0e10cSrcweir 								const B2DPoint& rPoint = pPNCurr->maPoint;
614*cdf0e10cSrcweir 								aNewPart.append(rPoint);
615*cdf0e10cSrcweir 
616*cdf0e10cSrcweir 								if(mbIsCurve)
617*cdf0e10cSrcweir 								{
618*cdf0e10cSrcweir 				                    const VN& rVNCurr = maVNV[pPNCurr->mnI];
619*cdf0e10cSrcweir 
620*cdf0e10cSrcweir 									if(!rVNCurr.maPrev.equalZero())
621*cdf0e10cSrcweir 									{
622*cdf0e10cSrcweir 										aNewPart.setPrevControlPoint(aNewPart.count() - 1, rPoint + rVNCurr.maPrev);
623*cdf0e10cSrcweir 									}
624*cdf0e10cSrcweir 
625*cdf0e10cSrcweir 									if(!rVNCurr.maNext.equalZero())
626*cdf0e10cSrcweir 									{
627*cdf0e10cSrcweir 										aNewPart.setNextControlPoint(aNewPart.count() - 1, rPoint + rVNCurr.maNext);
628*cdf0e10cSrcweir 									}
629*cdf0e10cSrcweir 								}
630*cdf0e10cSrcweir 
631*cdf0e10cSrcweir 								pPNCurr->mnI = SAL_MAX_UINT32;
632*cdf0e10cSrcweir 								nCountdown--;
633*cdf0e10cSrcweir 								pPNCurr = &(maPNV[pPNCurr->mnIN]);
634*cdf0e10cSrcweir 							}
635*cdf0e10cSrcweir 							while(pPNCurr != &rPN && SAL_MAX_UINT32 != pPNCurr->mnI);
636*cdf0e10cSrcweir 
637*cdf0e10cSrcweir 							// close and add
638*cdf0e10cSrcweir 							aNewPart.setClosed(true);
639*cdf0e10cSrcweir 							aRetval.append(aNewPart);
640*cdf0e10cSrcweir 						}
641*cdf0e10cSrcweir 					}
642*cdf0e10cSrcweir 
643*cdf0e10cSrcweir 					return aRetval;
644*cdf0e10cSrcweir 				}
645*cdf0e10cSrcweir 				else
646*cdf0e10cSrcweir 				{
647*cdf0e10cSrcweir 					// no change, return original
648*cdf0e10cSrcweir 					return maOriginal;
649*cdf0e10cSrcweir 				}
650*cdf0e10cSrcweir 			}
651*cdf0e10cSrcweir         };
652*cdf0e10cSrcweir 
653*cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////////////
654*cdf0e10cSrcweir 
655*cdf0e10cSrcweir 	} // end of anonymous namespace
656*cdf0e10cSrcweir } // end of namespace basegfx
657*cdf0e10cSrcweir 
658*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
659*cdf0e10cSrcweir 
660*cdf0e10cSrcweir namespace basegfx
661*cdf0e10cSrcweir {
662*cdf0e10cSrcweir 	namespace tools
663*cdf0e10cSrcweir 	{
664*cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////////////
665*cdf0e10cSrcweir 
666*cdf0e10cSrcweir 		B2DPolyPolygon solveCrossovers(const B2DPolyPolygon& rCandidate)
667*cdf0e10cSrcweir 		{
668*cdf0e10cSrcweir 			if(rCandidate.count() > 1L)
669*cdf0e10cSrcweir 			{
670*cdf0e10cSrcweir 				solver aSolver(rCandidate);
671*cdf0e10cSrcweir 				return aSolver.getB2DPolyPolygon();
672*cdf0e10cSrcweir 			}
673*cdf0e10cSrcweir 			else
674*cdf0e10cSrcweir 			{
675*cdf0e10cSrcweir 				return rCandidate;
676*cdf0e10cSrcweir 			}
677*cdf0e10cSrcweir 		}
678*cdf0e10cSrcweir 
679*cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////////////
680*cdf0e10cSrcweir 
681*cdf0e10cSrcweir 		B2DPolyPolygon solveCrossovers(const B2DPolygon& rCandidate)
682*cdf0e10cSrcweir 		{
683*cdf0e10cSrcweir 			solver aSolver(rCandidate);
684*cdf0e10cSrcweir 			return aSolver.getB2DPolyPolygon();
685*cdf0e10cSrcweir 		}
686*cdf0e10cSrcweir 
687*cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////////////
688*cdf0e10cSrcweir 
689*cdf0e10cSrcweir 		B2DPolyPolygon stripNeutralPolygons(const B2DPolyPolygon& rCandidate)
690*cdf0e10cSrcweir 		{
691*cdf0e10cSrcweir 			B2DPolyPolygon aRetval;
692*cdf0e10cSrcweir 
693*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
694*cdf0e10cSrcweir 			{
695*cdf0e10cSrcweir 				const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
696*cdf0e10cSrcweir 
697*cdf0e10cSrcweir 				if(ORIENTATION_NEUTRAL != tools::getOrientation(aCandidate))
698*cdf0e10cSrcweir 				{
699*cdf0e10cSrcweir 					aRetval.append(aCandidate);
700*cdf0e10cSrcweir 				}
701*cdf0e10cSrcweir 			}
702*cdf0e10cSrcweir 
703*cdf0e10cSrcweir 			return aRetval;
704*cdf0e10cSrcweir 		}
705*cdf0e10cSrcweir 
706*cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////////////
707*cdf0e10cSrcweir 
708*cdf0e10cSrcweir 		B2DPolyPolygon stripDispensablePolygons(const B2DPolyPolygon& rCandidate, bool bKeepAboveZero)
709*cdf0e10cSrcweir 		{
710*cdf0e10cSrcweir 			const sal_uInt32 nCount(rCandidate.count());
711*cdf0e10cSrcweir 			B2DPolyPolygon aRetval;
712*cdf0e10cSrcweir 
713*cdf0e10cSrcweir 			if(nCount)
714*cdf0e10cSrcweir 			{
715*cdf0e10cSrcweir 				if(nCount == 1L)
716*cdf0e10cSrcweir 				{
717*cdf0e10cSrcweir 					if(!bKeepAboveZero && ORIENTATION_POSITIVE == tools::getOrientation(rCandidate.getB2DPolygon(0L)))
718*cdf0e10cSrcweir 					{
719*cdf0e10cSrcweir 						aRetval = rCandidate;
720*cdf0e10cSrcweir 					}
721*cdf0e10cSrcweir 				}
722*cdf0e10cSrcweir 				else
723*cdf0e10cSrcweir 				{
724*cdf0e10cSrcweir 					sal_uInt32 a, b;
725*cdf0e10cSrcweir 					::std::vector< StripHelper > aHelpers;
726*cdf0e10cSrcweir 					aHelpers.resize(nCount);
727*cdf0e10cSrcweir 
728*cdf0e10cSrcweir 					for(a = 0L; a < nCount; a++)
729*cdf0e10cSrcweir 					{
730*cdf0e10cSrcweir 						const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
731*cdf0e10cSrcweir 						StripHelper* pNewHelper = &(aHelpers[a]);
732*cdf0e10cSrcweir 						pNewHelper->maRange = tools::getRange(aCandidate);
733*cdf0e10cSrcweir 						pNewHelper->meOrinetation = tools::getOrientation(aCandidate);
734*cdf0e10cSrcweir 						pNewHelper->mnDepth = (ORIENTATION_NEGATIVE == pNewHelper->meOrinetation ? -1L : 0L);
735*cdf0e10cSrcweir 					}
736*cdf0e10cSrcweir 
737*cdf0e10cSrcweir 					for(a = 0L; a < nCount - 1L; a++)
738*cdf0e10cSrcweir 					{
739*cdf0e10cSrcweir 						const B2DPolygon aCandA(rCandidate.getB2DPolygon(a));
740*cdf0e10cSrcweir 						StripHelper& rHelperA = aHelpers[a];
741*cdf0e10cSrcweir 
742*cdf0e10cSrcweir 						for(b = a + 1L; b < nCount; b++)
743*cdf0e10cSrcweir 						{
744*cdf0e10cSrcweir 							const B2DPolygon aCandB(rCandidate.getB2DPolygon(b));
745*cdf0e10cSrcweir 							StripHelper& rHelperB = aHelpers[b];
746*cdf0e10cSrcweir 							const bool bAInB(rHelperB.maRange.isInside(rHelperA.maRange) && tools::isInside(aCandB, aCandA, true));
747*cdf0e10cSrcweir 							const bool bBInA(rHelperA.maRange.isInside(rHelperB.maRange) && tools::isInside(aCandA, aCandB, true));
748*cdf0e10cSrcweir 
749*cdf0e10cSrcweir 							if(bAInB && bBInA)
750*cdf0e10cSrcweir 							{
751*cdf0e10cSrcweir 								// congruent
752*cdf0e10cSrcweir 								if(rHelperA.meOrinetation == rHelperB.meOrinetation)
753*cdf0e10cSrcweir 								{
754*cdf0e10cSrcweir 									// two polys or two holes. Lower one of them to get one of them out of the way.
755*cdf0e10cSrcweir 									// Since each will be contained in the other one, both will be increased, too.
756*cdf0e10cSrcweir 									// So, for lowering, increase only one of them
757*cdf0e10cSrcweir 									rHelperA.mnDepth++;
758*cdf0e10cSrcweir 								}
759*cdf0e10cSrcweir 								else
760*cdf0e10cSrcweir 								{
761*cdf0e10cSrcweir 									// poly and hole. They neutralize, so get rid of both. Move securely below zero.
762*cdf0e10cSrcweir 									rHelperA.mnDepth = -((sal_Int32)nCount);
763*cdf0e10cSrcweir 									rHelperB.mnDepth = -((sal_Int32)nCount);
764*cdf0e10cSrcweir 								}
765*cdf0e10cSrcweir 							}
766*cdf0e10cSrcweir 							else
767*cdf0e10cSrcweir 							{
768*cdf0e10cSrcweir 								if(bAInB)
769*cdf0e10cSrcweir 								{
770*cdf0e10cSrcweir 									if(ORIENTATION_NEGATIVE == rHelperB.meOrinetation)
771*cdf0e10cSrcweir 									{
772*cdf0e10cSrcweir 										rHelperA.mnDepth--;
773*cdf0e10cSrcweir 									}
774*cdf0e10cSrcweir 									else
775*cdf0e10cSrcweir 									{
776*cdf0e10cSrcweir 										rHelperA.mnDepth++;
777*cdf0e10cSrcweir 									}
778*cdf0e10cSrcweir 								}
779*cdf0e10cSrcweir 								else if(bBInA)
780*cdf0e10cSrcweir 								{
781*cdf0e10cSrcweir 									if(ORIENTATION_NEGATIVE == rHelperA.meOrinetation)
782*cdf0e10cSrcweir 									{
783*cdf0e10cSrcweir 										rHelperB.mnDepth--;
784*cdf0e10cSrcweir 									}
785*cdf0e10cSrcweir 									else
786*cdf0e10cSrcweir 									{
787*cdf0e10cSrcweir 										rHelperB.mnDepth++;
788*cdf0e10cSrcweir 									}
789*cdf0e10cSrcweir 								}
790*cdf0e10cSrcweir 							}
791*cdf0e10cSrcweir 						}
792*cdf0e10cSrcweir 					}
793*cdf0e10cSrcweir 
794*cdf0e10cSrcweir 					for(a = 0L; a < nCount; a++)
795*cdf0e10cSrcweir 					{
796*cdf0e10cSrcweir 						const StripHelper& rHelper = aHelpers[a];
797*cdf0e10cSrcweir 						bool bAcceptEntry(bKeepAboveZero ? 1L <= rHelper.mnDepth : 0L == rHelper.mnDepth);
798*cdf0e10cSrcweir 
799*cdf0e10cSrcweir 						if(bAcceptEntry)
800*cdf0e10cSrcweir 						{
801*cdf0e10cSrcweir 							aRetval.append(rCandidate.getB2DPolygon(a));
802*cdf0e10cSrcweir 						}
803*cdf0e10cSrcweir 					}
804*cdf0e10cSrcweir 				}
805*cdf0e10cSrcweir 			}
806*cdf0e10cSrcweir 
807*cdf0e10cSrcweir 			return aRetval;
808*cdf0e10cSrcweir 		}
809*cdf0e10cSrcweir 
810*cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////////////
811*cdf0e10cSrcweir 
812*cdf0e10cSrcweir         B2DPolyPolygon prepareForPolygonOperation(const B2DPolygon& rCandidate)
813*cdf0e10cSrcweir         {
814*cdf0e10cSrcweir 			solver aSolver(rCandidate);
815*cdf0e10cSrcweir 			B2DPolyPolygon aRetval(stripNeutralPolygons(aSolver.getB2DPolyPolygon()));
816*cdf0e10cSrcweir 
817*cdf0e10cSrcweir             return correctOrientations(aRetval);
818*cdf0e10cSrcweir         }
819*cdf0e10cSrcweir 
820*cdf0e10cSrcweir         B2DPolyPolygon prepareForPolygonOperation(const B2DPolyPolygon& rCandidate)
821*cdf0e10cSrcweir         {
822*cdf0e10cSrcweir 			solver aSolver(rCandidate);
823*cdf0e10cSrcweir 			B2DPolyPolygon aRetval(stripNeutralPolygons(aSolver.getB2DPolyPolygon()));
824*cdf0e10cSrcweir 
825*cdf0e10cSrcweir             return correctOrientations(aRetval);
826*cdf0e10cSrcweir         }
827*cdf0e10cSrcweir 
828*cdf0e10cSrcweir         B2DPolyPolygon solvePolygonOperationOr(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
829*cdf0e10cSrcweir         {
830*cdf0e10cSrcweir             if(!rCandidateA.count())
831*cdf0e10cSrcweir             {
832*cdf0e10cSrcweir                 return rCandidateB;
833*cdf0e10cSrcweir             }
834*cdf0e10cSrcweir             else if(!rCandidateB.count())
835*cdf0e10cSrcweir             {
836*cdf0e10cSrcweir                 return rCandidateA;
837*cdf0e10cSrcweir             }
838*cdf0e10cSrcweir             else
839*cdf0e10cSrcweir             {
840*cdf0e10cSrcweir                 // concatenate polygons, solve crossovers and throw away all sub-polygons
841*cdf0e10cSrcweir                 // which have a depth other than 0.
842*cdf0e10cSrcweir                 B2DPolyPolygon aRetval(rCandidateA);
843*cdf0e10cSrcweir 
844*cdf0e10cSrcweir                 aRetval.append(rCandidateB);
845*cdf0e10cSrcweir 			    aRetval = solveCrossovers(aRetval);
846*cdf0e10cSrcweir 			    aRetval = stripNeutralPolygons(aRetval);
847*cdf0e10cSrcweir 
848*cdf0e10cSrcweir                 return stripDispensablePolygons(aRetval, false);
849*cdf0e10cSrcweir             }
850*cdf0e10cSrcweir         }
851*cdf0e10cSrcweir 
852*cdf0e10cSrcweir         B2DPolyPolygon solvePolygonOperationXor(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
853*cdf0e10cSrcweir         {
854*cdf0e10cSrcweir             if(!rCandidateA.count())
855*cdf0e10cSrcweir             {
856*cdf0e10cSrcweir                 return rCandidateB;
857*cdf0e10cSrcweir             }
858*cdf0e10cSrcweir             else if(!rCandidateB.count())
859*cdf0e10cSrcweir             {
860*cdf0e10cSrcweir                 return rCandidateA;
861*cdf0e10cSrcweir             }
862*cdf0e10cSrcweir             else
863*cdf0e10cSrcweir             {
864*cdf0e10cSrcweir                 // XOR is pretty simple: By definition it is the simple concatenation of
865*cdf0e10cSrcweir                 // the single polygons since we imply XOR fill rule. Make it intersection-free
866*cdf0e10cSrcweir                 // and correct orientations
867*cdf0e10cSrcweir                 B2DPolyPolygon aRetval(rCandidateA);
868*cdf0e10cSrcweir 
869*cdf0e10cSrcweir                 aRetval.append(rCandidateB);
870*cdf0e10cSrcweir 			    aRetval = solveCrossovers(aRetval);
871*cdf0e10cSrcweir 			    aRetval = stripNeutralPolygons(aRetval);
872*cdf0e10cSrcweir 
873*cdf0e10cSrcweir                 return correctOrientations(aRetval);
874*cdf0e10cSrcweir             }
875*cdf0e10cSrcweir         }
876*cdf0e10cSrcweir 
877*cdf0e10cSrcweir         B2DPolyPolygon solvePolygonOperationAnd(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
878*cdf0e10cSrcweir         {
879*cdf0e10cSrcweir             if(!rCandidateA.count())
880*cdf0e10cSrcweir             {
881*cdf0e10cSrcweir                 return B2DPolyPolygon();
882*cdf0e10cSrcweir             }
883*cdf0e10cSrcweir             else if(!rCandidateB.count())
884*cdf0e10cSrcweir             {
885*cdf0e10cSrcweir                 return B2DPolyPolygon();
886*cdf0e10cSrcweir             }
887*cdf0e10cSrcweir             else
888*cdf0e10cSrcweir             {
889*cdf0e10cSrcweir                 // concatenate polygons, solve crossovers and throw away all sub-polygons
890*cdf0e10cSrcweir                 // with a depth of < 1. This means to keep all polygons where at least two
891*cdf0e10cSrcweir                 // polygons do overlap.
892*cdf0e10cSrcweir                 B2DPolyPolygon aRetval(rCandidateA);
893*cdf0e10cSrcweir 
894*cdf0e10cSrcweir                 aRetval.append(rCandidateB);
895*cdf0e10cSrcweir 			    aRetval = solveCrossovers(aRetval);
896*cdf0e10cSrcweir 			    aRetval = stripNeutralPolygons(aRetval);
897*cdf0e10cSrcweir 
898*cdf0e10cSrcweir                 return stripDispensablePolygons(aRetval, true);
899*cdf0e10cSrcweir             }
900*cdf0e10cSrcweir         }
901*cdf0e10cSrcweir 
902*cdf0e10cSrcweir         B2DPolyPolygon solvePolygonOperationDiff(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
903*cdf0e10cSrcweir         {
904*cdf0e10cSrcweir             if(!rCandidateA.count())
905*cdf0e10cSrcweir             {
906*cdf0e10cSrcweir                 return B2DPolyPolygon();
907*cdf0e10cSrcweir             }
908*cdf0e10cSrcweir             else if(!rCandidateB.count())
909*cdf0e10cSrcweir             {
910*cdf0e10cSrcweir                 return rCandidateA;
911*cdf0e10cSrcweir             }
912*cdf0e10cSrcweir             else
913*cdf0e10cSrcweir             {
914*cdf0e10cSrcweir 			    // Make B topologically to holes and append to A
915*cdf0e10cSrcweir                 B2DPolyPolygon aRetval(rCandidateB);
916*cdf0e10cSrcweir 
917*cdf0e10cSrcweir                 aRetval.flip();
918*cdf0e10cSrcweir                 aRetval.append(rCandidateA);
919*cdf0e10cSrcweir 
920*cdf0e10cSrcweir                 // solve crossovers and throw away all sub-polygons which have a
921*cdf0e10cSrcweir                 // depth other than 0.
922*cdf0e10cSrcweir 			    aRetval = basegfx::tools::solveCrossovers(aRetval);
923*cdf0e10cSrcweir 			    aRetval = basegfx::tools::stripNeutralPolygons(aRetval);
924*cdf0e10cSrcweir 
925*cdf0e10cSrcweir                 return basegfx::tools::stripDispensablePolygons(aRetval, false);
926*cdf0e10cSrcweir             }
927*cdf0e10cSrcweir         }
928*cdf0e10cSrcweir 
929*cdf0e10cSrcweir 		B2DPolyPolygon mergeToSinglePolyPolygon(const std::vector< basegfx::B2DPolyPolygon >& rInput)
930*cdf0e10cSrcweir 		{
931*cdf0e10cSrcweir 			std::vector< basegfx::B2DPolyPolygon > aInput(rInput);
932*cdf0e10cSrcweir 
933*cdf0e10cSrcweir 			// first step: prepareForPolygonOperation and simple merge of non-overlapping
934*cdf0e10cSrcweir 			// PolyPolygons for speedup; this is possible for the wanted OR-operation
935*cdf0e10cSrcweir 			if(aInput.size())
936*cdf0e10cSrcweir 			{
937*cdf0e10cSrcweir 				std::vector< basegfx::B2DPolyPolygon > aResult;
938*cdf0e10cSrcweir 				aResult.reserve(aInput.size());
939*cdf0e10cSrcweir 
940*cdf0e10cSrcweir 				for(sal_uInt32 a(0); a < aInput.size(); a++)
941*cdf0e10cSrcweir 				{
942*cdf0e10cSrcweir 					const basegfx::B2DPolyPolygon aCandidate(prepareForPolygonOperation(aInput[a]));
943*cdf0e10cSrcweir 
944*cdf0e10cSrcweir 					if(aResult.size())
945*cdf0e10cSrcweir 					{
946*cdf0e10cSrcweir 				        const B2DRange aCandidateRange(aCandidate.getB2DRange());
947*cdf0e10cSrcweir 						bool bCouldMergeSimple(false);
948*cdf0e10cSrcweir 
949*cdf0e10cSrcweir 						for(sal_uInt32 b(0); !bCouldMergeSimple && b < aResult.size(); b++)
950*cdf0e10cSrcweir 						{
951*cdf0e10cSrcweir 							basegfx::B2DPolyPolygon aTarget(aResult[b]);
952*cdf0e10cSrcweir 					        const B2DRange aTargetRange(aTarget.getB2DRange());
953*cdf0e10cSrcweir 
954*cdf0e10cSrcweir 							if(!aCandidateRange.overlaps(aTargetRange))
955*cdf0e10cSrcweir 							{
956*cdf0e10cSrcweir 								aTarget.append(aCandidate);
957*cdf0e10cSrcweir 								aResult[b] = aTarget;
958*cdf0e10cSrcweir 								bCouldMergeSimple = true;
959*cdf0e10cSrcweir 							}
960*cdf0e10cSrcweir 						}
961*cdf0e10cSrcweir 
962*cdf0e10cSrcweir 						if(!bCouldMergeSimple)
963*cdf0e10cSrcweir 						{
964*cdf0e10cSrcweir 							aResult.push_back(aCandidate);
965*cdf0e10cSrcweir 						}
966*cdf0e10cSrcweir 					}
967*cdf0e10cSrcweir 					else
968*cdf0e10cSrcweir 					{
969*cdf0e10cSrcweir 						aResult.push_back(aCandidate);
970*cdf0e10cSrcweir 					}
971*cdf0e10cSrcweir 				}
972*cdf0e10cSrcweir 
973*cdf0e10cSrcweir 				aInput = aResult;
974*cdf0e10cSrcweir 			}
975*cdf0e10cSrcweir 
976*cdf0e10cSrcweir 			// second step: melt pairwise to a single PolyPolygon
977*cdf0e10cSrcweir 			while(aInput.size() > 1)
978*cdf0e10cSrcweir 			{
979*cdf0e10cSrcweir 				std::vector< basegfx::B2DPolyPolygon > aResult;
980*cdf0e10cSrcweir 				aResult.reserve((aInput.size() / 2) + 1);
981*cdf0e10cSrcweir 
982*cdf0e10cSrcweir 				for(sal_uInt32 a(0); a < aInput.size(); a += 2)
983*cdf0e10cSrcweir 				{
984*cdf0e10cSrcweir 					if(a + 1 < aInput.size())
985*cdf0e10cSrcweir 					{
986*cdf0e10cSrcweir 						// a pair for processing
987*cdf0e10cSrcweir 						aResult.push_back(solvePolygonOperationOr(aInput[a], aInput[a + 1]));
988*cdf0e10cSrcweir 					}
989*cdf0e10cSrcweir 					else
990*cdf0e10cSrcweir 					{
991*cdf0e10cSrcweir 						// last single PolyPolygon; copy to target to not lose it
992*cdf0e10cSrcweir 						aResult.push_back(aInput[a]);
993*cdf0e10cSrcweir 					}
994*cdf0e10cSrcweir 				}
995*cdf0e10cSrcweir 
996*cdf0e10cSrcweir 				aInput = aResult;
997*cdf0e10cSrcweir 			}
998*cdf0e10cSrcweir 
999*cdf0e10cSrcweir 			// third step: get result
1000*cdf0e10cSrcweir 			if(1 == aInput.size())
1001*cdf0e10cSrcweir 			{
1002*cdf0e10cSrcweir 				return aInput[0];
1003*cdf0e10cSrcweir 			}
1004*cdf0e10cSrcweir 
1005*cdf0e10cSrcweir 			return B2DPolyPolygon();
1006*cdf0e10cSrcweir 		}
1007*cdf0e10cSrcweir 
1008*cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////////////
1009*cdf0e10cSrcweir 
1010*cdf0e10cSrcweir 	} // end of namespace tools
1011*cdf0e10cSrcweir } // end of namespace basegfx
1012*cdf0e10cSrcweir 
1013*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
1014*cdf0e10cSrcweir // eof
1015