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