1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_basegfx.hxx"
30*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx>
31*cdf0e10cSrcweir #include <osl/diagnose.h>
32*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygon.hxx>
33*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx>
34*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
35*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx>
36*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
37*cdf0e10cSrcweir 
38*cdf0e10cSrcweir #include <numeric>
39*cdf0e10cSrcweir 
40*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
41*cdf0e10cSrcweir 
42*cdf0e10cSrcweir namespace basegfx
43*cdf0e10cSrcweir {
44*cdf0e10cSrcweir 	namespace tools
45*cdf0e10cSrcweir 	{
46*cdf0e10cSrcweir 		B2DPolyPolygon correctOrientations(const B2DPolyPolygon& rCandidate)
47*cdf0e10cSrcweir 		{
48*cdf0e10cSrcweir 			B2DPolyPolygon aRetval(rCandidate);
49*cdf0e10cSrcweir 			const sal_uInt32 nCount(aRetval.count());
50*cdf0e10cSrcweir 
51*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < nCount; a++)
52*cdf0e10cSrcweir 			{
53*cdf0e10cSrcweir 				const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
54*cdf0e10cSrcweir 				const B2VectorOrientation aOrientation(tools::getOrientation(aCandidate));
55*cdf0e10cSrcweir 				sal_uInt32 nDepth(0L);
56*cdf0e10cSrcweir 
57*cdf0e10cSrcweir 				for(sal_uInt32 b(0L); b < nCount; b++)
58*cdf0e10cSrcweir 				{
59*cdf0e10cSrcweir 					if(b != a)
60*cdf0e10cSrcweir 					{
61*cdf0e10cSrcweir 						const B2DPolygon aCompare(rCandidate.getB2DPolygon(b));
62*cdf0e10cSrcweir 
63*cdf0e10cSrcweir 						if(tools::isInside(aCompare, aCandidate, true))
64*cdf0e10cSrcweir 						{
65*cdf0e10cSrcweir 							nDepth++;
66*cdf0e10cSrcweir 						}
67*cdf0e10cSrcweir 					}
68*cdf0e10cSrcweir 				}
69*cdf0e10cSrcweir 
70*cdf0e10cSrcweir 				const bool bShallBeHole(1L == (nDepth & 0x00000001));
71*cdf0e10cSrcweir 				const bool bIsHole(ORIENTATION_NEGATIVE == aOrientation);
72*cdf0e10cSrcweir 
73*cdf0e10cSrcweir 				if(bShallBeHole != bIsHole && ORIENTATION_NEUTRAL != aOrientation)
74*cdf0e10cSrcweir 				{
75*cdf0e10cSrcweir 					B2DPolygon aFlipped(aCandidate);
76*cdf0e10cSrcweir 					aFlipped.flip();
77*cdf0e10cSrcweir 					aRetval.setB2DPolygon(a, aFlipped);
78*cdf0e10cSrcweir 				}
79*cdf0e10cSrcweir 			}
80*cdf0e10cSrcweir 
81*cdf0e10cSrcweir 			return aRetval;
82*cdf0e10cSrcweir 		}
83*cdf0e10cSrcweir 
84*cdf0e10cSrcweir 		B2DPolyPolygon correctOutmostPolygon(const B2DPolyPolygon& rCandidate)
85*cdf0e10cSrcweir 		{
86*cdf0e10cSrcweir 			const sal_uInt32 nCount(rCandidate.count());
87*cdf0e10cSrcweir 
88*cdf0e10cSrcweir 			if(nCount > 1L)
89*cdf0e10cSrcweir 			{
90*cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nCount; a++)
91*cdf0e10cSrcweir 				{
92*cdf0e10cSrcweir 					const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
93*cdf0e10cSrcweir 					sal_uInt32 nDepth(0L);
94*cdf0e10cSrcweir 
95*cdf0e10cSrcweir 					for(sal_uInt32 b(0L); b < nCount; b++)
96*cdf0e10cSrcweir 					{
97*cdf0e10cSrcweir 						if(b != a)
98*cdf0e10cSrcweir 						{
99*cdf0e10cSrcweir 							const B2DPolygon aCompare(rCandidate.getB2DPolygon(b));
100*cdf0e10cSrcweir 
101*cdf0e10cSrcweir 							if(tools::isInside(aCompare, aCandidate, true))
102*cdf0e10cSrcweir 							{
103*cdf0e10cSrcweir 								nDepth++;
104*cdf0e10cSrcweir 							}
105*cdf0e10cSrcweir 						}
106*cdf0e10cSrcweir 					}
107*cdf0e10cSrcweir 
108*cdf0e10cSrcweir 					if(!nDepth)
109*cdf0e10cSrcweir 					{
110*cdf0e10cSrcweir 						B2DPolyPolygon aRetval(rCandidate);
111*cdf0e10cSrcweir 
112*cdf0e10cSrcweir 						if(a != 0L)
113*cdf0e10cSrcweir 						{
114*cdf0e10cSrcweir 							// exchange polygon a and polygon 0L
115*cdf0e10cSrcweir 							aRetval.setB2DPolygon(0L, aCandidate);
116*cdf0e10cSrcweir 							aRetval.setB2DPolygon(a, rCandidate.getB2DPolygon(0L));
117*cdf0e10cSrcweir 						}
118*cdf0e10cSrcweir 
119*cdf0e10cSrcweir 						// exit
120*cdf0e10cSrcweir 						return aRetval;
121*cdf0e10cSrcweir 					}
122*cdf0e10cSrcweir 				}
123*cdf0e10cSrcweir 			}
124*cdf0e10cSrcweir 
125*cdf0e10cSrcweir 			return rCandidate;
126*cdf0e10cSrcweir 		}
127*cdf0e10cSrcweir 
128*cdf0e10cSrcweir 		B2DPolyPolygon adaptiveSubdivideByDistance(const B2DPolyPolygon& rCandidate, double fDistanceBound)
129*cdf0e10cSrcweir 		{
130*cdf0e10cSrcweir 			if(rCandidate.areControlPointsUsed())
131*cdf0e10cSrcweir 			{
132*cdf0e10cSrcweir 				const sal_uInt32 nPolygonCount(rCandidate.count());
133*cdf0e10cSrcweir 				B2DPolyPolygon aRetval;
134*cdf0e10cSrcweir 
135*cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nPolygonCount; a++)
136*cdf0e10cSrcweir 				{
137*cdf0e10cSrcweir 					const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
138*cdf0e10cSrcweir 
139*cdf0e10cSrcweir 					if(aCandidate.areControlPointsUsed())
140*cdf0e10cSrcweir 					{
141*cdf0e10cSrcweir 						aRetval.append(tools::adaptiveSubdivideByDistance(aCandidate, fDistanceBound));
142*cdf0e10cSrcweir 					}
143*cdf0e10cSrcweir 					else
144*cdf0e10cSrcweir 					{
145*cdf0e10cSrcweir 						aRetval.append(aCandidate);
146*cdf0e10cSrcweir 					}
147*cdf0e10cSrcweir 				}
148*cdf0e10cSrcweir 
149*cdf0e10cSrcweir 				return aRetval;
150*cdf0e10cSrcweir 			}
151*cdf0e10cSrcweir 			else
152*cdf0e10cSrcweir 			{
153*cdf0e10cSrcweir 				return rCandidate;
154*cdf0e10cSrcweir 			}
155*cdf0e10cSrcweir 		}
156*cdf0e10cSrcweir 
157*cdf0e10cSrcweir 		B2DPolyPolygon adaptiveSubdivideByAngle(const B2DPolyPolygon& rCandidate, double fAngleBound)
158*cdf0e10cSrcweir 		{
159*cdf0e10cSrcweir 			if(rCandidate.areControlPointsUsed())
160*cdf0e10cSrcweir 			{
161*cdf0e10cSrcweir 				const sal_uInt32 nPolygonCount(rCandidate.count());
162*cdf0e10cSrcweir 				B2DPolyPolygon aRetval;
163*cdf0e10cSrcweir 
164*cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nPolygonCount; a++)
165*cdf0e10cSrcweir 				{
166*cdf0e10cSrcweir 					const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
167*cdf0e10cSrcweir 
168*cdf0e10cSrcweir 					if(aCandidate.areControlPointsUsed())
169*cdf0e10cSrcweir 					{
170*cdf0e10cSrcweir 						aRetval.append(tools::adaptiveSubdivideByAngle(aCandidate, fAngleBound));
171*cdf0e10cSrcweir 					}
172*cdf0e10cSrcweir 					else
173*cdf0e10cSrcweir 					{
174*cdf0e10cSrcweir 						aRetval.append(aCandidate);
175*cdf0e10cSrcweir 					}
176*cdf0e10cSrcweir 				}
177*cdf0e10cSrcweir 
178*cdf0e10cSrcweir 				return aRetval;
179*cdf0e10cSrcweir 			}
180*cdf0e10cSrcweir 			else
181*cdf0e10cSrcweir 			{
182*cdf0e10cSrcweir 				return rCandidate;
183*cdf0e10cSrcweir 			}
184*cdf0e10cSrcweir 		}
185*cdf0e10cSrcweir 
186*cdf0e10cSrcweir 		B2DPolyPolygon adaptiveSubdivideByCount(const B2DPolyPolygon& rCandidate, sal_uInt32 nCount)
187*cdf0e10cSrcweir 		{
188*cdf0e10cSrcweir 			if(rCandidate.areControlPointsUsed())
189*cdf0e10cSrcweir 			{
190*cdf0e10cSrcweir 				const sal_uInt32 nPolygonCount(rCandidate.count());
191*cdf0e10cSrcweir 				B2DPolyPolygon aRetval;
192*cdf0e10cSrcweir 
193*cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nPolygonCount; a++)
194*cdf0e10cSrcweir 				{
195*cdf0e10cSrcweir 					const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
196*cdf0e10cSrcweir 
197*cdf0e10cSrcweir 					if(aCandidate.areControlPointsUsed())
198*cdf0e10cSrcweir 					{
199*cdf0e10cSrcweir 						aRetval.append(tools::adaptiveSubdivideByCount(aCandidate, nCount));
200*cdf0e10cSrcweir 					}
201*cdf0e10cSrcweir 					else
202*cdf0e10cSrcweir 					{
203*cdf0e10cSrcweir 						aRetval.append(aCandidate);
204*cdf0e10cSrcweir 					}
205*cdf0e10cSrcweir 				}
206*cdf0e10cSrcweir 
207*cdf0e10cSrcweir 				return aRetval;
208*cdf0e10cSrcweir 			}
209*cdf0e10cSrcweir 			else
210*cdf0e10cSrcweir 			{
211*cdf0e10cSrcweir 				return rCandidate;
212*cdf0e10cSrcweir 			}
213*cdf0e10cSrcweir 		}
214*cdf0e10cSrcweir 
215*cdf0e10cSrcweir 		bool isInside(const B2DPolyPolygon& rCandidate, const B2DPoint& rPoint, bool bWithBorder)
216*cdf0e10cSrcweir 		{
217*cdf0e10cSrcweir 			const sal_uInt32 nPolygonCount(rCandidate.count());
218*cdf0e10cSrcweir 
219*cdf0e10cSrcweir 			if(1L == nPolygonCount)
220*cdf0e10cSrcweir 			{
221*cdf0e10cSrcweir 				return isInside(rCandidate.getB2DPolygon(0L), rPoint, bWithBorder);
222*cdf0e10cSrcweir 			}
223*cdf0e10cSrcweir 			else
224*cdf0e10cSrcweir 			{
225*cdf0e10cSrcweir 				sal_Int32 nInsideCount(0L);
226*cdf0e10cSrcweir 
227*cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nPolygonCount; a++)
228*cdf0e10cSrcweir 				{
229*cdf0e10cSrcweir 					const B2DPolygon aPolygon(rCandidate.getB2DPolygon(a));
230*cdf0e10cSrcweir 					const bool bInside(isInside(aPolygon, rPoint, bWithBorder));
231*cdf0e10cSrcweir 
232*cdf0e10cSrcweir 					if(bInside)
233*cdf0e10cSrcweir 					{
234*cdf0e10cSrcweir 						nInsideCount++;
235*cdf0e10cSrcweir 					}
236*cdf0e10cSrcweir 				}
237*cdf0e10cSrcweir 
238*cdf0e10cSrcweir 				return (nInsideCount % 2L);
239*cdf0e10cSrcweir 			}
240*cdf0e10cSrcweir 		}
241*cdf0e10cSrcweir 
242*cdf0e10cSrcweir 		B2DRange getRangeWithControlPoints(const B2DPolyPolygon& rCandidate)
243*cdf0e10cSrcweir 		{
244*cdf0e10cSrcweir 			B2DRange aRetval;
245*cdf0e10cSrcweir 			const sal_uInt32 nPolygonCount(rCandidate.count());
246*cdf0e10cSrcweir 
247*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
248*cdf0e10cSrcweir 			{
249*cdf0e10cSrcweir 				B2DPolygon aCandidate = rCandidate.getB2DPolygon(a);
250*cdf0e10cSrcweir 				aRetval.expand(tools::getRangeWithControlPoints(aCandidate));
251*cdf0e10cSrcweir 			}
252*cdf0e10cSrcweir 
253*cdf0e10cSrcweir 			return aRetval;
254*cdf0e10cSrcweir 		}
255*cdf0e10cSrcweir 
256*cdf0e10cSrcweir 		B2DRange getRange(const B2DPolyPolygon& rCandidate)
257*cdf0e10cSrcweir 		{
258*cdf0e10cSrcweir 			B2DRange aRetval;
259*cdf0e10cSrcweir 			const sal_uInt32 nPolygonCount(rCandidate.count());
260*cdf0e10cSrcweir 
261*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
262*cdf0e10cSrcweir 			{
263*cdf0e10cSrcweir 				B2DPolygon aCandidate = rCandidate.getB2DPolygon(a);
264*cdf0e10cSrcweir 				aRetval.expand(tools::getRange(aCandidate));
265*cdf0e10cSrcweir 			}
266*cdf0e10cSrcweir 
267*cdf0e10cSrcweir 			return aRetval;
268*cdf0e10cSrcweir 		}
269*cdf0e10cSrcweir 
270*cdf0e10cSrcweir 		void applyLineDashing(const B2DPolyPolygon& rCandidate, const ::std::vector<double>& rDotDashArray, B2DPolyPolygon* pLineTarget, B2DPolyPolygon* pGapTarget, double fFullDashDotLen)
271*cdf0e10cSrcweir 		{
272*cdf0e10cSrcweir 			if(0.0 == fFullDashDotLen && rDotDashArray.size())
273*cdf0e10cSrcweir 			{
274*cdf0e10cSrcweir 				// calculate fFullDashDotLen from rDotDashArray
275*cdf0e10cSrcweir 				fFullDashDotLen = ::std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
276*cdf0e10cSrcweir 			}
277*cdf0e10cSrcweir 
278*cdf0e10cSrcweir 			if(rCandidate.count() && fFullDashDotLen > 0.0)
279*cdf0e10cSrcweir 			{
280*cdf0e10cSrcweir 				B2DPolyPolygon aLineTarget, aGapTarget;
281*cdf0e10cSrcweir 
282*cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
283*cdf0e10cSrcweir 				{
284*cdf0e10cSrcweir 					const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
285*cdf0e10cSrcweir 
286*cdf0e10cSrcweir 					applyLineDashing(
287*cdf0e10cSrcweir 						aCandidate,
288*cdf0e10cSrcweir 						rDotDashArray,
289*cdf0e10cSrcweir 						pLineTarget ? &aLineTarget : 0,
290*cdf0e10cSrcweir 						pGapTarget ? &aGapTarget : 0,
291*cdf0e10cSrcweir 						fFullDashDotLen);
292*cdf0e10cSrcweir 
293*cdf0e10cSrcweir 					if(pLineTarget)
294*cdf0e10cSrcweir 					{
295*cdf0e10cSrcweir 						pLineTarget->append(aLineTarget);
296*cdf0e10cSrcweir 					}
297*cdf0e10cSrcweir 
298*cdf0e10cSrcweir 					if(pGapTarget)
299*cdf0e10cSrcweir 					{
300*cdf0e10cSrcweir 						pGapTarget->append(aGapTarget);
301*cdf0e10cSrcweir 					}
302*cdf0e10cSrcweir 				}
303*cdf0e10cSrcweir 			}
304*cdf0e10cSrcweir 		}
305*cdf0e10cSrcweir 
306*cdf0e10cSrcweir 		bool isInEpsilonRange(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPosition, double fDistance)
307*cdf0e10cSrcweir 		{
308*cdf0e10cSrcweir 			const sal_uInt32 nPolygonCount(rCandidate.count());
309*cdf0e10cSrcweir 
310*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
311*cdf0e10cSrcweir 			{
312*cdf0e10cSrcweir 				B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
313*cdf0e10cSrcweir 
314*cdf0e10cSrcweir 				if(isInEpsilonRange(aCandidate, rTestPosition, fDistance))
315*cdf0e10cSrcweir 				{
316*cdf0e10cSrcweir 					return true;
317*cdf0e10cSrcweir 				}
318*cdf0e10cSrcweir 			}
319*cdf0e10cSrcweir 
320*cdf0e10cSrcweir 			return false;
321*cdf0e10cSrcweir 		}
322*cdf0e10cSrcweir 
323*cdf0e10cSrcweir 		B3DPolyPolygon createB3DPolyPolygonFromB2DPolyPolygon(const B2DPolyPolygon& rCandidate, double fZCoordinate)
324*cdf0e10cSrcweir 		{
325*cdf0e10cSrcweir 			const sal_uInt32 nPolygonCount(rCandidate.count());
326*cdf0e10cSrcweir 			B3DPolyPolygon aRetval;
327*cdf0e10cSrcweir 
328*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
329*cdf0e10cSrcweir 			{
330*cdf0e10cSrcweir 				B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
331*cdf0e10cSrcweir 
332*cdf0e10cSrcweir 				aRetval.append(createB3DPolygonFromB2DPolygon(aCandidate, fZCoordinate));
333*cdf0e10cSrcweir 			}
334*cdf0e10cSrcweir 
335*cdf0e10cSrcweir 			return aRetval;
336*cdf0e10cSrcweir 		}
337*cdf0e10cSrcweir 
338*cdf0e10cSrcweir 		B2DPolyPolygon createB2DPolyPolygonFromB3DPolyPolygon(const B3DPolyPolygon& rCandidate, const B3DHomMatrix& rMat)
339*cdf0e10cSrcweir 		{
340*cdf0e10cSrcweir 			const sal_uInt32 nPolygonCount(rCandidate.count());
341*cdf0e10cSrcweir 			B2DPolyPolygon aRetval;
342*cdf0e10cSrcweir 
343*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
344*cdf0e10cSrcweir 			{
345*cdf0e10cSrcweir 				B3DPolygon aCandidate(rCandidate.getB3DPolygon(a));
346*cdf0e10cSrcweir 
347*cdf0e10cSrcweir 				aRetval.append(createB2DPolygonFromB3DPolygon(aCandidate, rMat));
348*cdf0e10cSrcweir 			}
349*cdf0e10cSrcweir 
350*cdf0e10cSrcweir 			return aRetval;
351*cdf0e10cSrcweir 		}
352*cdf0e10cSrcweir 
353*cdf0e10cSrcweir 		double getSmallestDistancePointToPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPoint, sal_uInt32& rPolygonIndex, sal_uInt32& rEdgeIndex, double& rCut)
354*cdf0e10cSrcweir 		{
355*cdf0e10cSrcweir 			double fRetval(DBL_MAX);
356*cdf0e10cSrcweir 			const double fZero(0.0);
357*cdf0e10cSrcweir 			const sal_uInt32 nPolygonCount(rCandidate.count());
358*cdf0e10cSrcweir 
359*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
360*cdf0e10cSrcweir 			{
361*cdf0e10cSrcweir 				const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
362*cdf0e10cSrcweir 				sal_uInt32 nNewEdgeIndex;
363*cdf0e10cSrcweir 				double fNewCut;
364*cdf0e10cSrcweir 				const double fNewDistance(getSmallestDistancePointToPolygon(aCandidate, rTestPoint, nNewEdgeIndex, fNewCut));
365*cdf0e10cSrcweir 
366*cdf0e10cSrcweir 				if(DBL_MAX == fRetval || fNewDistance < fRetval)
367*cdf0e10cSrcweir 				{
368*cdf0e10cSrcweir 					fRetval = fNewDistance;
369*cdf0e10cSrcweir 					rPolygonIndex = a;
370*cdf0e10cSrcweir 					rEdgeIndex = nNewEdgeIndex;
371*cdf0e10cSrcweir 					rCut = fNewCut;
372*cdf0e10cSrcweir 
373*cdf0e10cSrcweir 					if(fTools::equal(fRetval, fZero))
374*cdf0e10cSrcweir 					{
375*cdf0e10cSrcweir 						// already found zero distance, cannot get better. Ensure numerical zero value and end loop.
376*cdf0e10cSrcweir 						fRetval = 0.0;
377*cdf0e10cSrcweir 						break;
378*cdf0e10cSrcweir 					}
379*cdf0e10cSrcweir 				}
380*cdf0e10cSrcweir 			}
381*cdf0e10cSrcweir 
382*cdf0e10cSrcweir 			return fRetval;
383*cdf0e10cSrcweir 		}
384*cdf0e10cSrcweir 
385*cdf0e10cSrcweir 		B2DPolyPolygon distort(const B2DPolyPolygon& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight)
386*cdf0e10cSrcweir 		{
387*cdf0e10cSrcweir 			const sal_uInt32 nPolygonCount(rCandidate.count());
388*cdf0e10cSrcweir 			B2DPolyPolygon aRetval;
389*cdf0e10cSrcweir 
390*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
391*cdf0e10cSrcweir 			{
392*cdf0e10cSrcweir 				const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
393*cdf0e10cSrcweir 
394*cdf0e10cSrcweir 				aRetval.append(distort(aCandidate, rOriginal, rTopLeft, rTopRight, rBottomLeft, rBottomRight));
395*cdf0e10cSrcweir 			}
396*cdf0e10cSrcweir 
397*cdf0e10cSrcweir 			return aRetval;
398*cdf0e10cSrcweir 		}
399*cdf0e10cSrcweir 
400*cdf0e10cSrcweir 		B2DPolyPolygon rotateAroundPoint(const B2DPolyPolygon& rCandidate, const B2DPoint& rCenter, double fAngle)
401*cdf0e10cSrcweir 		{
402*cdf0e10cSrcweir 			const sal_uInt32 nPolygonCount(rCandidate.count());
403*cdf0e10cSrcweir 			B2DPolyPolygon aRetval;
404*cdf0e10cSrcweir 
405*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
406*cdf0e10cSrcweir 			{
407*cdf0e10cSrcweir 				const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
408*cdf0e10cSrcweir 
409*cdf0e10cSrcweir 				aRetval.append(rotateAroundPoint(aCandidate, rCenter, fAngle));
410*cdf0e10cSrcweir 			}
411*cdf0e10cSrcweir 
412*cdf0e10cSrcweir 			return aRetval;
413*cdf0e10cSrcweir 		}
414*cdf0e10cSrcweir 
415*cdf0e10cSrcweir 		B2DPolyPolygon expandToCurve(const B2DPolyPolygon& rCandidate)
416*cdf0e10cSrcweir 		{
417*cdf0e10cSrcweir 			const sal_uInt32 nPolygonCount(rCandidate.count());
418*cdf0e10cSrcweir 			B2DPolyPolygon aRetval;
419*cdf0e10cSrcweir 
420*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < nPolygonCount; a++)
421*cdf0e10cSrcweir 			{
422*cdf0e10cSrcweir 				const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
423*cdf0e10cSrcweir 
424*cdf0e10cSrcweir 				aRetval.append(expandToCurve(aCandidate));
425*cdf0e10cSrcweir 			}
426*cdf0e10cSrcweir 
427*cdf0e10cSrcweir 			return aRetval;
428*cdf0e10cSrcweir 		}
429*cdf0e10cSrcweir 
430*cdf0e10cSrcweir 		B2DPolyPolygon setContinuity(const B2DPolyPolygon& rCandidate, B2VectorContinuity eContinuity)
431*cdf0e10cSrcweir 		{
432*cdf0e10cSrcweir 			if(rCandidate.areControlPointsUsed())
433*cdf0e10cSrcweir 			{
434*cdf0e10cSrcweir 				const sal_uInt32 nPolygonCount(rCandidate.count());
435*cdf0e10cSrcweir 				B2DPolyPolygon aRetval;
436*cdf0e10cSrcweir 
437*cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nPolygonCount; a++)
438*cdf0e10cSrcweir 				{
439*cdf0e10cSrcweir 					const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
440*cdf0e10cSrcweir 
441*cdf0e10cSrcweir 					aRetval.append(setContinuity(aCandidate, eContinuity));
442*cdf0e10cSrcweir 				}
443*cdf0e10cSrcweir 
444*cdf0e10cSrcweir 				return aRetval;
445*cdf0e10cSrcweir 			}
446*cdf0e10cSrcweir 			else
447*cdf0e10cSrcweir 			{
448*cdf0e10cSrcweir 				return rCandidate;
449*cdf0e10cSrcweir 			}
450*cdf0e10cSrcweir 		}
451*cdf0e10cSrcweir 
452*cdf0e10cSrcweir 		B2DPolyPolygon growInNormalDirection(const B2DPolyPolygon& rCandidate, double fValue)
453*cdf0e10cSrcweir 		{
454*cdf0e10cSrcweir 			if(0.0 != fValue)
455*cdf0e10cSrcweir 			{
456*cdf0e10cSrcweir 				B2DPolyPolygon aRetval;
457*cdf0e10cSrcweir 
458*cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
459*cdf0e10cSrcweir 				{
460*cdf0e10cSrcweir 					aRetval.append(growInNormalDirection(rCandidate.getB2DPolygon(a), fValue));
461*cdf0e10cSrcweir 				}
462*cdf0e10cSrcweir 
463*cdf0e10cSrcweir 				return aRetval;
464*cdf0e10cSrcweir 			}
465*cdf0e10cSrcweir 			else
466*cdf0e10cSrcweir 			{
467*cdf0e10cSrcweir 				return rCandidate;
468*cdf0e10cSrcweir 			}
469*cdf0e10cSrcweir 		}
470*cdf0e10cSrcweir 
471*cdf0e10cSrcweir 		void correctGrowShrinkPolygonPair(B2DPolyPolygon& /*rOriginal*/, B2DPolyPolygon& /*rGrown*/)
472*cdf0e10cSrcweir 		{
473*cdf0e10cSrcweir 		}
474*cdf0e10cSrcweir 
475*cdf0e10cSrcweir 		B2DPolyPolygon reSegmentPolyPolygon(const B2DPolyPolygon& rCandidate, sal_uInt32 nSegments)
476*cdf0e10cSrcweir 		{
477*cdf0e10cSrcweir 			B2DPolyPolygon aRetval;
478*cdf0e10cSrcweir 
479*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
480*cdf0e10cSrcweir 			{
481*cdf0e10cSrcweir 				aRetval.append(reSegmentPolygon(rCandidate.getB2DPolygon(a), nSegments));
482*cdf0e10cSrcweir 			}
483*cdf0e10cSrcweir 
484*cdf0e10cSrcweir 			return aRetval;
485*cdf0e10cSrcweir 		}
486*cdf0e10cSrcweir 
487*cdf0e10cSrcweir 		B2DPolyPolygon interpolate(const B2DPolyPolygon& rOld1, const B2DPolyPolygon& rOld2, double t)
488*cdf0e10cSrcweir 		{
489*cdf0e10cSrcweir 			OSL_ENSURE(rOld1.count() == rOld2.count(), "B2DPolyPolygon interpolate: Different geometry (!)");
490*cdf0e10cSrcweir 			B2DPolyPolygon aRetval;
491*cdf0e10cSrcweir 
492*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < rOld1.count(); a++)
493*cdf0e10cSrcweir 			{
494*cdf0e10cSrcweir 				aRetval.append(interpolate(rOld1.getB2DPolygon(a), rOld2.getB2DPolygon(a), t));
495*cdf0e10cSrcweir 			}
496*cdf0e10cSrcweir 
497*cdf0e10cSrcweir 			return aRetval;
498*cdf0e10cSrcweir 		}
499*cdf0e10cSrcweir 
500*cdf0e10cSrcweir         bool isRectangle( const B2DPolyPolygon& rPoly )
501*cdf0e10cSrcweir         {
502*cdf0e10cSrcweir             // exclude some cheap cases first
503*cdf0e10cSrcweir             if( rPoly.count() != 1 )
504*cdf0e10cSrcweir                 return false;
505*cdf0e10cSrcweir 
506*cdf0e10cSrcweir             return isRectangle( rPoly.getB2DPolygon(0) );
507*cdf0e10cSrcweir         }
508*cdf0e10cSrcweir 
509*cdf0e10cSrcweir 		// #i76891#
510*cdf0e10cSrcweir 		B2DPolyPolygon simplifyCurveSegments(const B2DPolyPolygon& rCandidate)
511*cdf0e10cSrcweir 		{
512*cdf0e10cSrcweir 			if(rCandidate.areControlPointsUsed())
513*cdf0e10cSrcweir 			{
514*cdf0e10cSrcweir 				B2DPolyPolygon aRetval;
515*cdf0e10cSrcweir 
516*cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
517*cdf0e10cSrcweir 				{
518*cdf0e10cSrcweir 					aRetval.append(simplifyCurveSegments(rCandidate.getB2DPolygon(a)));
519*cdf0e10cSrcweir 				}
520*cdf0e10cSrcweir 
521*cdf0e10cSrcweir 				return aRetval;
522*cdf0e10cSrcweir 			}
523*cdf0e10cSrcweir 			else
524*cdf0e10cSrcweir 			{
525*cdf0e10cSrcweir 				return rCandidate;
526*cdf0e10cSrcweir 			}
527*cdf0e10cSrcweir 		}
528*cdf0e10cSrcweir 
529*cdf0e10cSrcweir 		B2DPolyPolygon reSegmentPolyPolygonEdges(const B2DPolyPolygon& rCandidate, sal_uInt32 nSubEdges, bool bHandleCurvedEdges, bool bHandleStraightEdges)
530*cdf0e10cSrcweir         {
531*cdf0e10cSrcweir 			B2DPolyPolygon aRetval;
532*cdf0e10cSrcweir 
533*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
534*cdf0e10cSrcweir 			{
535*cdf0e10cSrcweir 				aRetval.append(reSegmentPolygonEdges(rCandidate.getB2DPolygon(a), nSubEdges, bHandleCurvedEdges, bHandleStraightEdges));
536*cdf0e10cSrcweir 			}
537*cdf0e10cSrcweir 
538*cdf0e10cSrcweir 			return aRetval;
539*cdf0e10cSrcweir         }
540*cdf0e10cSrcweir 
541*cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////
542*cdf0e10cSrcweir 		// comparators with tolerance for 2D PolyPolygons
543*cdf0e10cSrcweir 
544*cdf0e10cSrcweir 		bool equal(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB, const double& rfSmallValue)
545*cdf0e10cSrcweir 		{
546*cdf0e10cSrcweir 			const sal_uInt32 nPolygonCount(rCandidateA.count());
547*cdf0e10cSrcweir 
548*cdf0e10cSrcweir 			if(nPolygonCount != rCandidateB.count())
549*cdf0e10cSrcweir 				return false;
550*cdf0e10cSrcweir 
551*cdf0e10cSrcweir 			for(sal_uInt32 a(0); a < nPolygonCount; a++)
552*cdf0e10cSrcweir 			{
553*cdf0e10cSrcweir 				const B2DPolygon aCandidate(rCandidateA.getB2DPolygon(a));
554*cdf0e10cSrcweir 
555*cdf0e10cSrcweir 				if(!equal(aCandidate, rCandidateB.getB2DPolygon(a), rfSmallValue))
556*cdf0e10cSrcweir 					return false;
557*cdf0e10cSrcweir 			}
558*cdf0e10cSrcweir 
559*cdf0e10cSrcweir 			return true;
560*cdf0e10cSrcweir 		}
561*cdf0e10cSrcweir 
562*cdf0e10cSrcweir 		bool equal(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
563*cdf0e10cSrcweir 		{
564*cdf0e10cSrcweir 			const double fSmallValue(fTools::getSmallValue());
565*cdf0e10cSrcweir 
566*cdf0e10cSrcweir 			return equal(rCandidateA, rCandidateB, fSmallValue);
567*cdf0e10cSrcweir 		}
568*cdf0e10cSrcweir 
569*cdf0e10cSrcweir 		B2DPolyPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolyPolygon& rCandidate)
570*cdf0e10cSrcweir 		{
571*cdf0e10cSrcweir 			B2DPolyPolygon aRetval;
572*cdf0e10cSrcweir 
573*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
574*cdf0e10cSrcweir 			{
575*cdf0e10cSrcweir 				aRetval.append(snapPointsOfHorizontalOrVerticalEdges(rCandidate.getB2DPolygon(a)));
576*cdf0e10cSrcweir 			}
577*cdf0e10cSrcweir 
578*cdf0e10cSrcweir 			return aRetval;
579*cdf0e10cSrcweir 		}
580*cdf0e10cSrcweir 
581*cdf0e10cSrcweir 	} // end of namespace tools
582*cdf0e10cSrcweir } // end of namespace basegfx
583*cdf0e10cSrcweir 
584*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
585*cdf0e10cSrcweir // eof
586