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