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 <basegfx/numeric/ftools.hxx>
27cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
28cdf0e10cSrcweir #include <osl/diagnose.h>
29cdf0e10cSrcweir #include <rtl/math.hxx>
30cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx>
31cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygon.hxx>
32cdf0e10cSrcweir #include <basegfx/range/b2drange.hxx>
33cdf0e10cSrcweir #include <basegfx/curve/b2dcubicbezier.hxx>
34cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
35cdf0e10cSrcweir #include <basegfx/point/b3dpoint.hxx>
36cdf0e10cSrcweir #include <basegfx/matrix/b3dhommatrix.hxx>
37cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx>
38cdf0e10cSrcweir #include <basegfx/curve/b2dbeziertools.hxx>
39cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrixtools.hxx>
40cdf0e10cSrcweir #include <osl/mutex.hxx>
41cdf0e10cSrcweir 
42cdf0e10cSrcweir #include <numeric>
43cdf0e10cSrcweir #include <limits>
44cdf0e10cSrcweir 
45cdf0e10cSrcweir // #i37443#
46cdf0e10cSrcweir #define ANGLE_BOUND_START_VALUE		(2.25)
47cdf0e10cSrcweir #define ANGLE_BOUND_MINIMUM_VALUE	(0.1)
48cdf0e10cSrcweir #define COUNT_SUBDIVIDE_DEFAULT		(4L)
49cdf0e10cSrcweir #ifdef DBG_UTIL
50cdf0e10cSrcweir static double fAngleBoundStartValue = ANGLE_BOUND_START_VALUE;
51cdf0e10cSrcweir #endif
52cdf0e10cSrcweir #define STEPSPERQUARTER     (3)
53cdf0e10cSrcweir 
54cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
55cdf0e10cSrcweir 
56cdf0e10cSrcweir namespace basegfx
57cdf0e10cSrcweir {
58cdf0e10cSrcweir 	namespace tools
59cdf0e10cSrcweir 	{
openWithGeometryChange(B2DPolygon & rCandidate)60cdf0e10cSrcweir 		void openWithGeometryChange(B2DPolygon& rCandidate)
61cdf0e10cSrcweir 		{
62cdf0e10cSrcweir 			if(rCandidate.isClosed())
63cdf0e10cSrcweir 			{
64cdf0e10cSrcweir 				if(rCandidate.count())
65cdf0e10cSrcweir 				{
66cdf0e10cSrcweir 					rCandidate.append(rCandidate.getB2DPoint(0));
67cdf0e10cSrcweir 
68cdf0e10cSrcweir 					if(rCandidate.areControlPointsUsed() && rCandidate.isPrevControlPointUsed(0))
69cdf0e10cSrcweir 					{
70cdf0e10cSrcweir 						rCandidate.setPrevControlPoint(rCandidate.count() - 1, rCandidate.getPrevControlPoint(0));
71cdf0e10cSrcweir 						rCandidate.resetPrevControlPoint(0);
72cdf0e10cSrcweir 					}
73cdf0e10cSrcweir 				}
74cdf0e10cSrcweir 
75cdf0e10cSrcweir 				rCandidate.setClosed(false);
76cdf0e10cSrcweir 			}
77cdf0e10cSrcweir 		}
78cdf0e10cSrcweir 
closeWithGeometryChange(B2DPolygon & rCandidate)79cdf0e10cSrcweir 		void closeWithGeometryChange(B2DPolygon& rCandidate)
80cdf0e10cSrcweir 		{
81cdf0e10cSrcweir 			if(!rCandidate.isClosed())
82cdf0e10cSrcweir 			{
83cdf0e10cSrcweir 				while(rCandidate.count() > 1 && rCandidate.getB2DPoint(0) == rCandidate.getB2DPoint(rCandidate.count() - 1))
84cdf0e10cSrcweir 				{
85cdf0e10cSrcweir 					if(rCandidate.areControlPointsUsed() && rCandidate.isPrevControlPointUsed(rCandidate.count() - 1))
86cdf0e10cSrcweir 					{
87cdf0e10cSrcweir 						rCandidate.setPrevControlPoint(0, rCandidate.getPrevControlPoint(rCandidate.count() - 1));
88cdf0e10cSrcweir 					}
89cdf0e10cSrcweir 
90cdf0e10cSrcweir 					rCandidate.remove(rCandidate.count() - 1);
91cdf0e10cSrcweir 				}
92cdf0e10cSrcweir 
93cdf0e10cSrcweir 				rCandidate.setClosed(true);
94cdf0e10cSrcweir 			}
95cdf0e10cSrcweir 		}
96cdf0e10cSrcweir 
checkClosed(B2DPolygon & rCandidate)97cdf0e10cSrcweir 		void checkClosed(B2DPolygon& rCandidate)
98cdf0e10cSrcweir 		{
99cdf0e10cSrcweir 			// #i80172# Removed unnecessary assertion
100cdf0e10cSrcweir 			// OSL_ENSURE(!rCandidate.isClosed(), "checkClosed: already closed (!)");
101cdf0e10cSrcweir 
102cdf0e10cSrcweir 			if(rCandidate.count() > 1 && rCandidate.getB2DPoint(0) == rCandidate.getB2DPoint(rCandidate.count() - 1))
103cdf0e10cSrcweir 			{
104cdf0e10cSrcweir 				closeWithGeometryChange(rCandidate);
105cdf0e10cSrcweir 			}
106cdf0e10cSrcweir 		}
107cdf0e10cSrcweir 
108cdf0e10cSrcweir 		// Get successor and predecessor indices. Returning the same index means there
109cdf0e10cSrcweir 		// is none. Same for successor.
getIndexOfPredecessor(sal_uInt32 nIndex,const B2DPolygon & rCandidate)110cdf0e10cSrcweir 		sal_uInt32 getIndexOfPredecessor(sal_uInt32 nIndex, const B2DPolygon& rCandidate)
111cdf0e10cSrcweir 		{
112cdf0e10cSrcweir 			OSL_ENSURE(nIndex < rCandidate.count(), "getIndexOfPredecessor: Access to polygon out of range (!)");
113cdf0e10cSrcweir 
114cdf0e10cSrcweir 			if(nIndex)
115cdf0e10cSrcweir 			{
116cdf0e10cSrcweir 				return nIndex - 1L;
117cdf0e10cSrcweir 			}
118cdf0e10cSrcweir 			else if(rCandidate.count())
119cdf0e10cSrcweir 			{
120cdf0e10cSrcweir 				return rCandidate.count() - 1L;
121cdf0e10cSrcweir 			}
122cdf0e10cSrcweir 			else
123cdf0e10cSrcweir 			{
124cdf0e10cSrcweir 				return nIndex;
125cdf0e10cSrcweir 			}
126cdf0e10cSrcweir 		}
127cdf0e10cSrcweir 
getIndexOfSuccessor(sal_uInt32 nIndex,const B2DPolygon & rCandidate)128cdf0e10cSrcweir 		sal_uInt32 getIndexOfSuccessor(sal_uInt32 nIndex, const B2DPolygon& rCandidate)
129cdf0e10cSrcweir 		{
130cdf0e10cSrcweir 			OSL_ENSURE(nIndex < rCandidate.count(), "getIndexOfPredecessor: Access to polygon out of range (!)");
131cdf0e10cSrcweir 
132cdf0e10cSrcweir 			if(nIndex + 1L < rCandidate.count())
133cdf0e10cSrcweir 			{
134cdf0e10cSrcweir 				return nIndex + 1L;
135cdf0e10cSrcweir 			}
136cdf0e10cSrcweir 			else if(nIndex + 1L == rCandidate.count())
137cdf0e10cSrcweir 			{
138cdf0e10cSrcweir 				return 0L;
139cdf0e10cSrcweir 			}
140cdf0e10cSrcweir 			else
141cdf0e10cSrcweir 			{
142cdf0e10cSrcweir 				return nIndex;
143cdf0e10cSrcweir 			}
144cdf0e10cSrcweir 		}
145cdf0e10cSrcweir 
getOrientation(const B2DPolygon & rCandidate)146cdf0e10cSrcweir 		B2VectorOrientation getOrientation(const B2DPolygon& rCandidate)
147cdf0e10cSrcweir 		{
148cdf0e10cSrcweir 			B2VectorOrientation eRetval(ORIENTATION_NEUTRAL);
149cdf0e10cSrcweir 
150cdf0e10cSrcweir 			if(rCandidate.count() > 2L || rCandidate.areControlPointsUsed())
151cdf0e10cSrcweir 			{
152cdf0e10cSrcweir 				const double fSignedArea(getSignedArea(rCandidate));
153cdf0e10cSrcweir 
154cdf0e10cSrcweir 				if(fTools::equalZero(fSignedArea))
155cdf0e10cSrcweir 				{
156cdf0e10cSrcweir 					// ORIENTATION_NEUTRAL, already set
157cdf0e10cSrcweir 				}
158cdf0e10cSrcweir 				if(fSignedArea > 0.0)
159cdf0e10cSrcweir 				{
160cdf0e10cSrcweir 					eRetval = ORIENTATION_POSITIVE;
161cdf0e10cSrcweir 				}
162cdf0e10cSrcweir 				else if(fSignedArea < 0.0)
163cdf0e10cSrcweir 				{
164cdf0e10cSrcweir 					eRetval = ORIENTATION_NEGATIVE;
165cdf0e10cSrcweir 				}
166cdf0e10cSrcweir 			}
167cdf0e10cSrcweir 
168cdf0e10cSrcweir 			return eRetval;
169cdf0e10cSrcweir 		}
170cdf0e10cSrcweir 
getContinuityInPoint(const B2DPolygon & rCandidate,sal_uInt32 nIndex)171cdf0e10cSrcweir 		B2VectorContinuity getContinuityInPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndex)
172cdf0e10cSrcweir 		{
173cdf0e10cSrcweir 			return rCandidate.getContinuityInPoint(nIndex);
174cdf0e10cSrcweir 		}
175cdf0e10cSrcweir 
adaptiveSubdivideByDistance(const B2DPolygon & rCandidate,double fDistanceBound)176cdf0e10cSrcweir 		B2DPolygon adaptiveSubdivideByDistance(const B2DPolygon& rCandidate, double fDistanceBound)
177cdf0e10cSrcweir 		{
178cdf0e10cSrcweir 			if(rCandidate.areControlPointsUsed())
179cdf0e10cSrcweir 			{
180cdf0e10cSrcweir 				const sal_uInt32 nPointCount(rCandidate.count());
181cdf0e10cSrcweir 				B2DPolygon aRetval;
182cdf0e10cSrcweir 
183cdf0e10cSrcweir 				if(nPointCount)
184cdf0e10cSrcweir 				{
185cdf0e10cSrcweir 					// prepare edge-oriented loop
186cdf0e10cSrcweir 					const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
187cdf0e10cSrcweir 					B2DCubicBezier aBezier;
188cdf0e10cSrcweir 					aBezier.setStartPoint(rCandidate.getB2DPoint(0));
189cdf0e10cSrcweir 
190cdf0e10cSrcweir 					// perf: try to avoid too many realloctions by guessing the result's pointcount
191cdf0e10cSrcweir 					aRetval.reserve(nPointCount*4);
192cdf0e10cSrcweir 
193cdf0e10cSrcweir 					// add start point (always)
194cdf0e10cSrcweir 					aRetval.append(aBezier.getStartPoint());
195cdf0e10cSrcweir 
196cdf0e10cSrcweir 					for(sal_uInt32 a(0L); a < nEdgeCount; a++)
197cdf0e10cSrcweir 					{
198cdf0e10cSrcweir 						// get next and control points
199cdf0e10cSrcweir 						const sal_uInt32 nNextIndex((a + 1) % nPointCount);
200cdf0e10cSrcweir 						aBezier.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
201cdf0e10cSrcweir 						aBezier.setControlPointA(rCandidate.getNextControlPoint(a));
202cdf0e10cSrcweir 						aBezier.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
203cdf0e10cSrcweir 						aBezier.testAndSolveTrivialBezier();
204cdf0e10cSrcweir 
205cdf0e10cSrcweir 						if(aBezier.isBezier())
206cdf0e10cSrcweir 						{
207cdf0e10cSrcweir 							// add curved edge and generate DistanceBound
208cdf0e10cSrcweir 							double fBound(0.0);
209cdf0e10cSrcweir 
210cdf0e10cSrcweir 							if(0.0 == fDistanceBound)
211cdf0e10cSrcweir 							{
212cdf0e10cSrcweir 								// If not set, use B2DCubicBezier functionality to guess a rough value
213cdf0e10cSrcweir 								const double fRoughLength((aBezier.getEdgeLength() + aBezier.getControlPolygonLength()) / 2.0);
214cdf0e10cSrcweir 
215cdf0e10cSrcweir 								// take 1/100th of the rough curve length
216cdf0e10cSrcweir 								fBound = fRoughLength * 0.01;
217cdf0e10cSrcweir 							}
218cdf0e10cSrcweir 							else
219cdf0e10cSrcweir 							{
220cdf0e10cSrcweir 								// use given bound value
221cdf0e10cSrcweir 								fBound = fDistanceBound;
222cdf0e10cSrcweir 							}
223cdf0e10cSrcweir 
224cdf0e10cSrcweir 							// make sure bound value is not too small. The base units are 1/100th mm, thus
225cdf0e10cSrcweir 							// just make sure it's not smaller then 1/100th of that
226cdf0e10cSrcweir 							if(fBound < 0.01)
227cdf0e10cSrcweir 							{
228cdf0e10cSrcweir 								fBound = 0.01;
229cdf0e10cSrcweir 							}
230cdf0e10cSrcweir 
231cdf0e10cSrcweir 							// call adaptive subdivide which adds edges to aRetval accordingly
232cdf0e10cSrcweir 							aBezier.adaptiveSubdivideByDistance(aRetval, fBound);
233cdf0e10cSrcweir 						}
234cdf0e10cSrcweir 						else
235cdf0e10cSrcweir 						{
236cdf0e10cSrcweir 							// add non-curved edge
237cdf0e10cSrcweir 							aRetval.append(aBezier.getEndPoint());
238cdf0e10cSrcweir 						}
239cdf0e10cSrcweir 
240cdf0e10cSrcweir 						// prepare next step
241cdf0e10cSrcweir 						aBezier.setStartPoint(aBezier.getEndPoint());
242cdf0e10cSrcweir 					}
243cdf0e10cSrcweir 
244cdf0e10cSrcweir 					if(rCandidate.isClosed())
245cdf0e10cSrcweir 					{
246cdf0e10cSrcweir 						// set closed flag and correct last point (which is added double now).
247cdf0e10cSrcweir 						closeWithGeometryChange(aRetval);
248cdf0e10cSrcweir 					}
249cdf0e10cSrcweir 				}
250cdf0e10cSrcweir 
251cdf0e10cSrcweir 				return aRetval;
252cdf0e10cSrcweir 			}
253cdf0e10cSrcweir 			else
254cdf0e10cSrcweir 			{
255cdf0e10cSrcweir 				return rCandidate;
256cdf0e10cSrcweir 			}
257cdf0e10cSrcweir 		}
258cdf0e10cSrcweir 
adaptiveSubdivideByAngle(const B2DPolygon & rCandidate,double fAngleBound)259cdf0e10cSrcweir 		B2DPolygon adaptiveSubdivideByAngle(const B2DPolygon& rCandidate, double fAngleBound)
260cdf0e10cSrcweir 		{
261cdf0e10cSrcweir 			if(rCandidate.areControlPointsUsed())
262cdf0e10cSrcweir 			{
263cdf0e10cSrcweir 				const sal_uInt32 nPointCount(rCandidate.count());
264cdf0e10cSrcweir 				B2DPolygon aRetval;
265cdf0e10cSrcweir 
266cdf0e10cSrcweir 				if(nPointCount)
267cdf0e10cSrcweir 				{
268cdf0e10cSrcweir 					// prepare edge-oriented loop
269cdf0e10cSrcweir 					const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
270cdf0e10cSrcweir 					B2DCubicBezier aBezier;
271cdf0e10cSrcweir 					aBezier.setStartPoint(rCandidate.getB2DPoint(0));
272cdf0e10cSrcweir 
273cdf0e10cSrcweir 					// perf: try to avoid too many realloctions by guessing the result's pointcount
274cdf0e10cSrcweir 					aRetval.reserve(nPointCount*4);
275cdf0e10cSrcweir 
276cdf0e10cSrcweir 					// add start point (always)
277cdf0e10cSrcweir 					aRetval.append(aBezier.getStartPoint());
278cdf0e10cSrcweir 
279cdf0e10cSrcweir 					// #i37443# prepare convenient AngleBound if none was given
280cdf0e10cSrcweir 					if(0.0 == fAngleBound)
281cdf0e10cSrcweir 					{
282cdf0e10cSrcweir #ifdef DBG_UTIL
283cdf0e10cSrcweir 						fAngleBound = fAngleBoundStartValue;
284cdf0e10cSrcweir #else
285cdf0e10cSrcweir 						fAngleBound = ANGLE_BOUND_START_VALUE;
286cdf0e10cSrcweir #endif
287cdf0e10cSrcweir 					}
288cdf0e10cSrcweir 					else if(fTools::less(fAngleBound, ANGLE_BOUND_MINIMUM_VALUE))
289cdf0e10cSrcweir 					{
290cdf0e10cSrcweir 						fAngleBound = 0.1;
291cdf0e10cSrcweir 					}
292cdf0e10cSrcweir 
293cdf0e10cSrcweir 					for(sal_uInt32 a(0L); a < nEdgeCount; a++)
294cdf0e10cSrcweir 					{
295cdf0e10cSrcweir 						// get next and control points
296cdf0e10cSrcweir 						const sal_uInt32 nNextIndex((a + 1) % nPointCount);
297cdf0e10cSrcweir 						aBezier.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
298cdf0e10cSrcweir 						aBezier.setControlPointA(rCandidate.getNextControlPoint(a));
299cdf0e10cSrcweir 						aBezier.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
300cdf0e10cSrcweir 						aBezier.testAndSolveTrivialBezier();
301cdf0e10cSrcweir 
302cdf0e10cSrcweir 						if(aBezier.isBezier())
303cdf0e10cSrcweir 						{
304cdf0e10cSrcweir 							// call adaptive subdivide
305cdf0e10cSrcweir 							aBezier.adaptiveSubdivideByAngle(aRetval, fAngleBound, true);
306cdf0e10cSrcweir 						}
307cdf0e10cSrcweir 						else
308cdf0e10cSrcweir 						{
309cdf0e10cSrcweir 							// add non-curved edge
310cdf0e10cSrcweir 							aRetval.append(aBezier.getEndPoint());
311cdf0e10cSrcweir 						}
312cdf0e10cSrcweir 
313cdf0e10cSrcweir 						// prepare next step
314cdf0e10cSrcweir 						aBezier.setStartPoint(aBezier.getEndPoint());
315cdf0e10cSrcweir 					}
316cdf0e10cSrcweir 
317cdf0e10cSrcweir 					if(rCandidate.isClosed())
318cdf0e10cSrcweir 					{
319cdf0e10cSrcweir 						// set closed flag and correct last point (which is added double now).
320cdf0e10cSrcweir 						closeWithGeometryChange(aRetval);
321cdf0e10cSrcweir 					}
322cdf0e10cSrcweir 				}
323cdf0e10cSrcweir 
324cdf0e10cSrcweir 				return aRetval;
325cdf0e10cSrcweir 			}
326cdf0e10cSrcweir 			else
327cdf0e10cSrcweir 			{
328cdf0e10cSrcweir 				return rCandidate;
329cdf0e10cSrcweir 			}
330cdf0e10cSrcweir 		}
331cdf0e10cSrcweir 
adaptiveSubdivideByCount(const B2DPolygon & rCandidate,sal_uInt32 nCount)332cdf0e10cSrcweir 		B2DPolygon adaptiveSubdivideByCount(const B2DPolygon& rCandidate, sal_uInt32 nCount)
333cdf0e10cSrcweir 		{
334cdf0e10cSrcweir 			if(rCandidate.areControlPointsUsed())
335cdf0e10cSrcweir 			{
336cdf0e10cSrcweir 				const sal_uInt32 nPointCount(rCandidate.count());
337cdf0e10cSrcweir 				B2DPolygon aRetval;
338cdf0e10cSrcweir 
339cdf0e10cSrcweir 				if(nPointCount)
340cdf0e10cSrcweir 				{
341cdf0e10cSrcweir 					// prepare edge-oriented loop
342cdf0e10cSrcweir 					const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
343cdf0e10cSrcweir 					B2DCubicBezier aBezier;
344cdf0e10cSrcweir 					aBezier.setStartPoint(rCandidate.getB2DPoint(0));
345cdf0e10cSrcweir 
346cdf0e10cSrcweir 					// perf: try to avoid too many realloctions by guessing the result's pointcount
347cdf0e10cSrcweir 					aRetval.reserve(nPointCount*4);
348cdf0e10cSrcweir 
349cdf0e10cSrcweir 					// add start point (always)
350cdf0e10cSrcweir 					aRetval.append(aBezier.getStartPoint());
351cdf0e10cSrcweir 
352cdf0e10cSrcweir 					// #i37443# prepare convenient count if none was given
353cdf0e10cSrcweir 					if(0L == nCount)
354cdf0e10cSrcweir 					{
355cdf0e10cSrcweir 						nCount = COUNT_SUBDIVIDE_DEFAULT;
356cdf0e10cSrcweir 					}
357cdf0e10cSrcweir 
358cdf0e10cSrcweir 					for(sal_uInt32 a(0L); a < nEdgeCount; a++)
359cdf0e10cSrcweir 					{
360cdf0e10cSrcweir 						// get next and control points
361cdf0e10cSrcweir 						const sal_uInt32 nNextIndex((a + 1) % nPointCount);
362cdf0e10cSrcweir 						aBezier.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
363cdf0e10cSrcweir 						aBezier.setControlPointA(rCandidate.getNextControlPoint(a));
364cdf0e10cSrcweir 						aBezier.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
365cdf0e10cSrcweir 						aBezier.testAndSolveTrivialBezier();
366cdf0e10cSrcweir 
367cdf0e10cSrcweir 						if(aBezier.isBezier())
368cdf0e10cSrcweir 						{
369cdf0e10cSrcweir 							// call adaptive subdivide
370cdf0e10cSrcweir 							aBezier.adaptiveSubdivideByCount(aRetval, nCount);
371cdf0e10cSrcweir 						}
372cdf0e10cSrcweir 						else
373cdf0e10cSrcweir 						{
374cdf0e10cSrcweir 							// add non-curved edge
375cdf0e10cSrcweir 							aRetval.append(aBezier.getEndPoint());
376cdf0e10cSrcweir 						}
377cdf0e10cSrcweir 
378cdf0e10cSrcweir 						// prepare next step
379cdf0e10cSrcweir 						aBezier.setStartPoint(aBezier.getEndPoint());
380cdf0e10cSrcweir 					}
381cdf0e10cSrcweir 
382cdf0e10cSrcweir 					if(rCandidate.isClosed())
383cdf0e10cSrcweir 					{
384cdf0e10cSrcweir 						// set closed flag and correct last point (which is added double now).
385cdf0e10cSrcweir 						closeWithGeometryChange(aRetval);
386cdf0e10cSrcweir 					}
387cdf0e10cSrcweir 				}
388cdf0e10cSrcweir 
389cdf0e10cSrcweir 				return aRetval;
390cdf0e10cSrcweir 			}
391cdf0e10cSrcweir 			else
392cdf0e10cSrcweir 			{
393cdf0e10cSrcweir 				return rCandidate;
394cdf0e10cSrcweir 			}
395cdf0e10cSrcweir 		}
396cdf0e10cSrcweir 
isInside(const B2DPolygon & rCandidate,const B2DPoint & rPoint,bool bWithBorder)397cdf0e10cSrcweir 		bool isInside(const B2DPolygon& rCandidate, const B2DPoint& rPoint, bool bWithBorder)
398cdf0e10cSrcweir 		{
399cdf0e10cSrcweir 			const B2DPolygon aCandidate(rCandidate.areControlPointsUsed() ? rCandidate.getDefaultAdaptiveSubdivision() : rCandidate);
400cdf0e10cSrcweir 
401cdf0e10cSrcweir 			if(bWithBorder && isPointOnPolygon(aCandidate, rPoint, true))
402cdf0e10cSrcweir 			{
403cdf0e10cSrcweir 				return true;
404cdf0e10cSrcweir 			}
405cdf0e10cSrcweir 			else
406cdf0e10cSrcweir 			{
407cdf0e10cSrcweir 				bool bRetval(false);
408cdf0e10cSrcweir 				const sal_uInt32 nPointCount(aCandidate.count());
409cdf0e10cSrcweir 
410cdf0e10cSrcweir 				if(nPointCount)
411cdf0e10cSrcweir 				{
412cdf0e10cSrcweir 					B2DPoint aCurrentPoint(aCandidate.getB2DPoint(nPointCount - 1L));
413cdf0e10cSrcweir 
414cdf0e10cSrcweir 					for(sal_uInt32 a(0L); a < nPointCount; a++)
415cdf0e10cSrcweir 					{
416cdf0e10cSrcweir 						const B2DPoint aPreviousPoint(aCurrentPoint);
417cdf0e10cSrcweir 						aCurrentPoint = aCandidate.getB2DPoint(a);
418cdf0e10cSrcweir 
419cdf0e10cSrcweir 						// cross-over in Y?
420cdf0e10cSrcweir 						const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY()));
421cdf0e10cSrcweir 						const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY()));
422cdf0e10cSrcweir 
423cdf0e10cSrcweir 						if(bCompYA != bCompYB)
424cdf0e10cSrcweir 						{
425cdf0e10cSrcweir 							// cross-over in X?
426cdf0e10cSrcweir 							const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX()));
427cdf0e10cSrcweir 							const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX()));
428cdf0e10cSrcweir 
429cdf0e10cSrcweir 							if(bCompXA == bCompXB)
430cdf0e10cSrcweir 							{
431cdf0e10cSrcweir 								if(bCompXA)
432cdf0e10cSrcweir 								{
433cdf0e10cSrcweir 									bRetval = !bRetval;
434cdf0e10cSrcweir 								}
435cdf0e10cSrcweir 							}
436cdf0e10cSrcweir 							else
437cdf0e10cSrcweir 							{
438cdf0e10cSrcweir 								const double fCompare(
439cdf0e10cSrcweir 									aCurrentPoint.getX() - (aCurrentPoint.getY() - rPoint.getY()) *
440cdf0e10cSrcweir 									(aPreviousPoint.getX() - aCurrentPoint.getX()) /
441cdf0e10cSrcweir 									(aPreviousPoint.getY() - aCurrentPoint.getY()));
442cdf0e10cSrcweir 
443cdf0e10cSrcweir 								if(fTools::more(fCompare, rPoint.getX()))
444cdf0e10cSrcweir 								{
445cdf0e10cSrcweir 									bRetval = !bRetval;
446cdf0e10cSrcweir 								}
447cdf0e10cSrcweir 							}
448cdf0e10cSrcweir 						}
449cdf0e10cSrcweir 					}
450cdf0e10cSrcweir 				}
451cdf0e10cSrcweir 
452cdf0e10cSrcweir 				return bRetval;
453cdf0e10cSrcweir 			}
454cdf0e10cSrcweir 		}
455cdf0e10cSrcweir 
isInside(const B2DPolygon & rCandidate,const B2DPolygon & rPolygon,bool bWithBorder)456cdf0e10cSrcweir 		bool isInside(const B2DPolygon& rCandidate, const B2DPolygon& rPolygon, bool bWithBorder)
457cdf0e10cSrcweir 		{
458cdf0e10cSrcweir 			const B2DPolygon aCandidate(rCandidate.areControlPointsUsed() ? rCandidate.getDefaultAdaptiveSubdivision() : rCandidate);
459cdf0e10cSrcweir 			const B2DPolygon aPolygon(rPolygon.areControlPointsUsed() ? rPolygon.getDefaultAdaptiveSubdivision() : rPolygon);
460cdf0e10cSrcweir 			const sal_uInt32 nPointCount(aPolygon.count());
461cdf0e10cSrcweir 
462cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < nPointCount; a++)
463cdf0e10cSrcweir 			{
464cdf0e10cSrcweir 				const B2DPoint aTestPoint(aPolygon.getB2DPoint(a));
465cdf0e10cSrcweir 
466cdf0e10cSrcweir 				if(!isInside(aCandidate, aTestPoint, bWithBorder))
467cdf0e10cSrcweir 				{
468cdf0e10cSrcweir 					return false;
469cdf0e10cSrcweir 				}
470cdf0e10cSrcweir 			}
471cdf0e10cSrcweir 
472cdf0e10cSrcweir 			return true;
473cdf0e10cSrcweir 		}
474cdf0e10cSrcweir 
getRangeWithControlPoints(const B2DPolygon & rCandidate)475cdf0e10cSrcweir 		B2DRange getRangeWithControlPoints(const B2DPolygon& rCandidate)
476cdf0e10cSrcweir 		{
477cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
478cdf0e10cSrcweir 			B2DRange aRetval;
479cdf0e10cSrcweir 
480cdf0e10cSrcweir 			if(nPointCount)
481cdf0e10cSrcweir 			{
482cdf0e10cSrcweir 				const bool bControlPointsUsed(rCandidate.areControlPointsUsed());
483cdf0e10cSrcweir 
484cdf0e10cSrcweir 				for(sal_uInt32 a(0); a < nPointCount; a++)
485cdf0e10cSrcweir 				{
486cdf0e10cSrcweir 					aRetval.expand(rCandidate.getB2DPoint(a));
487cdf0e10cSrcweir 
488cdf0e10cSrcweir 					if(bControlPointsUsed)
489cdf0e10cSrcweir 					{
490cdf0e10cSrcweir 						aRetval.expand(rCandidate.getNextControlPoint(a));
491cdf0e10cSrcweir 						aRetval.expand(rCandidate.getPrevControlPoint(a));
492cdf0e10cSrcweir 					}
493cdf0e10cSrcweir 				}
494cdf0e10cSrcweir 			}
495cdf0e10cSrcweir 
496cdf0e10cSrcweir 			return aRetval;
497cdf0e10cSrcweir 		}
498cdf0e10cSrcweir 
getRange(const B2DPolygon & rCandidate)499cdf0e10cSrcweir 		B2DRange getRange(const B2DPolygon& rCandidate)
500cdf0e10cSrcweir 		{
501cdf0e10cSrcweir             // changed to use internally buffered version at B2DPolygon
502cdf0e10cSrcweir             return rCandidate.getB2DRange();
503cdf0e10cSrcweir 		}
504cdf0e10cSrcweir 
getSignedArea(const B2DPolygon & rCandidate)505cdf0e10cSrcweir 		double getSignedArea(const B2DPolygon& rCandidate)
506cdf0e10cSrcweir 		{
507cdf0e10cSrcweir 			const B2DPolygon aCandidate(rCandidate.areControlPointsUsed() ? rCandidate.getDefaultAdaptiveSubdivision() : rCandidate);
508cdf0e10cSrcweir 			double fRetval(0.0);
509cdf0e10cSrcweir 			const sal_uInt32 nPointCount(aCandidate.count());
510cdf0e10cSrcweir 
511cdf0e10cSrcweir 			if(nPointCount > 2)
512cdf0e10cSrcweir 			{
513cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nPointCount; a++)
514cdf0e10cSrcweir 				{
515cdf0e10cSrcweir 					const B2DPoint aPreviousPoint(aCandidate.getB2DPoint((!a) ? nPointCount - 1L : a - 1L));
516cdf0e10cSrcweir 					const B2DPoint aCurrentPoint(aCandidate.getB2DPoint(a));
517cdf0e10cSrcweir 
518cdf0e10cSrcweir 					fRetval += aPreviousPoint.getX() * aCurrentPoint.getY();
519cdf0e10cSrcweir 					fRetval -= aPreviousPoint.getY() * aCurrentPoint.getX();
520cdf0e10cSrcweir 				}
521cdf0e10cSrcweir 
522cdf0e10cSrcweir 				// correct to zero if small enough. Also test the quadratic
523cdf0e10cSrcweir 				// of the result since the precision is near quadratic due to
524cdf0e10cSrcweir 				// the algorithm
525cdf0e10cSrcweir 				if(fTools::equalZero(fRetval) || fTools::equalZero(fRetval * fRetval))
526cdf0e10cSrcweir 				{
527cdf0e10cSrcweir 					fRetval = 0.0;
528cdf0e10cSrcweir 				}
529cdf0e10cSrcweir 			}
530cdf0e10cSrcweir 
531cdf0e10cSrcweir 			return fRetval;
532cdf0e10cSrcweir 		}
533cdf0e10cSrcweir 
getArea(const B2DPolygon & rCandidate)534cdf0e10cSrcweir 		double getArea(const B2DPolygon& rCandidate)
535cdf0e10cSrcweir 		{
536cdf0e10cSrcweir 			double fRetval(0.0);
537cdf0e10cSrcweir 
538cdf0e10cSrcweir 			if(rCandidate.count() > 2 || rCandidate.areControlPointsUsed())
539cdf0e10cSrcweir 			{
540cdf0e10cSrcweir 				fRetval = getSignedArea(rCandidate);
541cdf0e10cSrcweir 				const double fZero(0.0);
542cdf0e10cSrcweir 
543cdf0e10cSrcweir 				if(fTools::less(fRetval, fZero))
544cdf0e10cSrcweir 				{
545cdf0e10cSrcweir 					fRetval = -fRetval;
546cdf0e10cSrcweir 				}
547cdf0e10cSrcweir 			}
548cdf0e10cSrcweir 
549cdf0e10cSrcweir 			return fRetval;
550cdf0e10cSrcweir 		}
551cdf0e10cSrcweir 
getEdgeLength(const B2DPolygon & rCandidate,sal_uInt32 nIndex)552cdf0e10cSrcweir 		double getEdgeLength(const B2DPolygon& rCandidate, sal_uInt32 nIndex)
553cdf0e10cSrcweir 		{
554cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
555cdf0e10cSrcweir 			OSL_ENSURE(nIndex < nPointCount, "getEdgeLength: Access to polygon out of range (!)");
556cdf0e10cSrcweir 			double fRetval(0.0);
557cdf0e10cSrcweir 
558cdf0e10cSrcweir             if(nPointCount)
559cdf0e10cSrcweir             {
560cdf0e10cSrcweir                 const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
561cdf0e10cSrcweir 
562cdf0e10cSrcweir                 if(rCandidate.areControlPointsUsed())
563cdf0e10cSrcweir                 {
564cdf0e10cSrcweir                     B2DCubicBezier aEdge;
565cdf0e10cSrcweir 
566cdf0e10cSrcweir                     aEdge.setStartPoint(rCandidate.getB2DPoint(nIndex));
567cdf0e10cSrcweir                     aEdge.setControlPointA(rCandidate.getNextControlPoint(nIndex));
568cdf0e10cSrcweir                     aEdge.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
569cdf0e10cSrcweir                     aEdge.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
570cdf0e10cSrcweir 
571cdf0e10cSrcweir                     fRetval = aEdge.getLength();
572cdf0e10cSrcweir                 }
573cdf0e10cSrcweir                 else
574cdf0e10cSrcweir                 {
575cdf0e10cSrcweir 					const B2DPoint aCurrent(rCandidate.getB2DPoint(nIndex));
576cdf0e10cSrcweir 					const B2DPoint aNext(rCandidate.getB2DPoint(nNextIndex));
577cdf0e10cSrcweir 
578cdf0e10cSrcweir                     fRetval = B2DVector(aNext - aCurrent).getLength();
579cdf0e10cSrcweir                 }
580cdf0e10cSrcweir             }
581cdf0e10cSrcweir 
582cdf0e10cSrcweir 			return fRetval;
583cdf0e10cSrcweir 		}
584cdf0e10cSrcweir 
getLength(const B2DPolygon & rCandidate)585cdf0e10cSrcweir 		double getLength(const B2DPolygon& rCandidate)
586cdf0e10cSrcweir 		{
587cdf0e10cSrcweir 			double fRetval(0.0);
588cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
589cdf0e10cSrcweir 
590cdf0e10cSrcweir 			if(nPointCount)
591cdf0e10cSrcweir 			{
592cdf0e10cSrcweir                 const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
593cdf0e10cSrcweir 
594cdf0e10cSrcweir                 if(rCandidate.areControlPointsUsed())
595cdf0e10cSrcweir                 {
596cdf0e10cSrcweir                     B2DCubicBezier aEdge;
597cdf0e10cSrcweir                     aEdge.setStartPoint(rCandidate.getB2DPoint(0));
598cdf0e10cSrcweir 
599cdf0e10cSrcweir                     for(sal_uInt32 a(0); a < nEdgeCount; a++)
600cdf0e10cSrcweir                     {
601cdf0e10cSrcweir                         const sal_uInt32 nNextIndex((a + 1) % nPointCount);
602cdf0e10cSrcweir                         aEdge.setControlPointA(rCandidate.getNextControlPoint(a));
603cdf0e10cSrcweir                         aEdge.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
604cdf0e10cSrcweir                         aEdge.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
605cdf0e10cSrcweir 
606cdf0e10cSrcweir                         fRetval += aEdge.getLength();
607cdf0e10cSrcweir                         aEdge.setStartPoint(aEdge.getEndPoint());
608cdf0e10cSrcweir                     }
609cdf0e10cSrcweir                 }
610cdf0e10cSrcweir                 else
611cdf0e10cSrcweir                 {
612cdf0e10cSrcweir                     B2DPoint aCurrent(rCandidate.getB2DPoint(0));
613cdf0e10cSrcweir 
614cdf0e10cSrcweir                     for(sal_uInt32 a(0); a < nEdgeCount; a++)
615cdf0e10cSrcweir                     {
616cdf0e10cSrcweir                         const sal_uInt32 nNextIndex((a + 1) % nPointCount);
617cdf0e10cSrcweir                         const B2DPoint aNext(rCandidate.getB2DPoint(nNextIndex));
618cdf0e10cSrcweir 
619cdf0e10cSrcweir                         fRetval += B2DVector(aNext - aCurrent).getLength();
620cdf0e10cSrcweir                         aCurrent = aNext;
621cdf0e10cSrcweir                     }
622cdf0e10cSrcweir                 }
623cdf0e10cSrcweir 			}
624cdf0e10cSrcweir 
625cdf0e10cSrcweir 			return fRetval;
626cdf0e10cSrcweir 		}
627cdf0e10cSrcweir 
getPositionAbsolute(const B2DPolygon & rCandidate,double fDistance,double fLength)628cdf0e10cSrcweir 		B2DPoint getPositionAbsolute(const B2DPolygon& rCandidate, double fDistance, double fLength)
629cdf0e10cSrcweir 		{
630cdf0e10cSrcweir 			B2DPoint aRetval;
631cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
632cdf0e10cSrcweir 
633cdf0e10cSrcweir 			if( 1L == nPointCount )
634cdf0e10cSrcweir             {
635cdf0e10cSrcweir                 // only one point (i.e. no edge) - simply take that point
636cdf0e10cSrcweir                 aRetval = rCandidate.getB2DPoint(0);
637cdf0e10cSrcweir             }
638cdf0e10cSrcweir 			else if(nPointCount > 1L)
639cdf0e10cSrcweir 			{
640cdf0e10cSrcweir                 const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
641cdf0e10cSrcweir 				sal_uInt32 nIndex(0L);
642cdf0e10cSrcweir 				bool bIndexDone(false);
643cdf0e10cSrcweir 
644cdf0e10cSrcweir 				// get length if not given
645cdf0e10cSrcweir 				if(fTools::equalZero(fLength))
646cdf0e10cSrcweir 				{
647cdf0e10cSrcweir 					fLength = getLength(rCandidate);
648cdf0e10cSrcweir 				}
649cdf0e10cSrcweir 
650cdf0e10cSrcweir 				if(fTools::less(fDistance, 0.0))
651cdf0e10cSrcweir 				{
652cdf0e10cSrcweir     				// handle fDistance < 0.0
653cdf0e10cSrcweir 					if(rCandidate.isClosed())
654cdf0e10cSrcweir 					{
655cdf0e10cSrcweir 						// if fDistance < 0.0 increment with multiple of fLength
656cdf0e10cSrcweir 						sal_uInt32 nCount(sal_uInt32(-fDistance / fLength));
657cdf0e10cSrcweir 						fDistance += double(nCount + 1L) * fLength;
658cdf0e10cSrcweir 					}
659cdf0e10cSrcweir 					else
660cdf0e10cSrcweir 					{
661cdf0e10cSrcweir 						// crop to polygon start
662cdf0e10cSrcweir 						fDistance = 0.0;
663cdf0e10cSrcweir 						bIndexDone = true;
664cdf0e10cSrcweir 					}
665cdf0e10cSrcweir 				}
666cdf0e10cSrcweir 				else if(fTools::moreOrEqual(fDistance, fLength))
667cdf0e10cSrcweir 				{
668cdf0e10cSrcweir     				// handle fDistance >= fLength
669cdf0e10cSrcweir 					if(rCandidate.isClosed())
670cdf0e10cSrcweir 					{
671cdf0e10cSrcweir 						// if fDistance >= fLength decrement with multiple of fLength
672cdf0e10cSrcweir 						sal_uInt32 nCount(sal_uInt32(fDistance / fLength));
673cdf0e10cSrcweir 						fDistance -= (double)(nCount) * fLength;
674cdf0e10cSrcweir 					}
675cdf0e10cSrcweir 					else
676cdf0e10cSrcweir 					{
677cdf0e10cSrcweir 						// crop to polygon end
678cdf0e10cSrcweir 						fDistance = 0.0;
679cdf0e10cSrcweir 						nIndex = nEdgeCount;
680cdf0e10cSrcweir 						bIndexDone = true;
681cdf0e10cSrcweir 					}
682cdf0e10cSrcweir 				}
683cdf0e10cSrcweir 
684cdf0e10cSrcweir 				// look for correct index. fDistance is now [0.0 .. fLength[
685cdf0e10cSrcweir     			double fEdgeLength(getEdgeLength(rCandidate, nIndex));
686cdf0e10cSrcweir 
687cdf0e10cSrcweir                 while(!bIndexDone)
688cdf0e10cSrcweir                 {
689cdf0e10cSrcweir                     // edge found must be on the half-open range
690cdf0e10cSrcweir                     // [0,fEdgeLength).
691cdf0e10cSrcweir                     // Note that in theory, we cannot move beyond
692cdf0e10cSrcweir                     // the last polygon point, since fDistance>=fLength
693cdf0e10cSrcweir                     // is checked above. Unfortunately, with floating-
694cdf0e10cSrcweir                     // point calculations, this case might happen.
695cdf0e10cSrcweir                     // Handled by nIndex check below
696cdf0e10cSrcweir                     if(nIndex < nEdgeCount && fTools::moreOrEqual(fDistance, fEdgeLength))
697cdf0e10cSrcweir 					{
698cdf0e10cSrcweir 						// go to next edge
699cdf0e10cSrcweir 						fDistance -= fEdgeLength;
700cdf0e10cSrcweir 						fEdgeLength = getEdgeLength(rCandidate, ++nIndex);
701cdf0e10cSrcweir 					}
702cdf0e10cSrcweir 					else
703cdf0e10cSrcweir 					{
704cdf0e10cSrcweir 						// it's on this edge, stop
705cdf0e10cSrcweir 						bIndexDone = true;
706cdf0e10cSrcweir 					}
707cdf0e10cSrcweir                 }
708cdf0e10cSrcweir 
709cdf0e10cSrcweir                 // get the point using nIndex
710cdf0e10cSrcweir 				aRetval = rCandidate.getB2DPoint(nIndex);
711cdf0e10cSrcweir 
712cdf0e10cSrcweir 				// if fDistance != 0.0, move that length on the edge. The edge
713cdf0e10cSrcweir 				// length is in fEdgeLength.
714cdf0e10cSrcweir 				if(!fTools::equalZero(fDistance))
715cdf0e10cSrcweir 				{
716cdf0e10cSrcweir                     if(fTools::moreOrEqual(fDistance, fEdgeLength))
717cdf0e10cSrcweir                     {
718cdf0e10cSrcweir                         // end point of choosen edge
719cdf0e10cSrcweir     			        const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
720cdf0e10cSrcweir 				        aRetval = rCandidate.getB2DPoint(nNextIndex);
721cdf0e10cSrcweir                     }
722cdf0e10cSrcweir                     else if(fTools::equalZero(fDistance))
723cdf0e10cSrcweir                     {
724cdf0e10cSrcweir                         // start point of choosen edge
725cdf0e10cSrcweir                         aRetval = aRetval;
726cdf0e10cSrcweir                     }
727cdf0e10cSrcweir                     else
728cdf0e10cSrcweir                     {
729cdf0e10cSrcweir                         // inside edge
730cdf0e10cSrcweir     			        const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
731cdf0e10cSrcweir 				        const B2DPoint aNextPoint(rCandidate.getB2DPoint(nNextIndex));
732cdf0e10cSrcweir 						bool bDone(false);
733cdf0e10cSrcweir 
734cdf0e10cSrcweir 					    // add calculated average value to the return value
735cdf0e10cSrcweir                         if(rCandidate.areControlPointsUsed())
736cdf0e10cSrcweir                         {
737cdf0e10cSrcweir                             // get as bezier segment
738cdf0e10cSrcweir                             const B2DCubicBezier aBezierSegment(
739cdf0e10cSrcweir                                 aRetval, rCandidate.getNextControlPoint(nIndex),
740cdf0e10cSrcweir                                 rCandidate.getPrevControlPoint(nNextIndex), aNextPoint);
741cdf0e10cSrcweir 
742cdf0e10cSrcweir                             if(aBezierSegment.isBezier())
743cdf0e10cSrcweir                             {
744cdf0e10cSrcweir                                 // use B2DCubicBezierHelper to bridge the non-linear gap between
745cdf0e10cSrcweir                                 // length and bezier distances
746cdf0e10cSrcweir                                 const B2DCubicBezierHelper aBezierSegmentHelper(aBezierSegment);
747cdf0e10cSrcweir                                 const double fBezierDistance(aBezierSegmentHelper.distanceToRelative(fDistance));
748cdf0e10cSrcweir 
749cdf0e10cSrcweir                                 aRetval = aBezierSegment.interpolatePoint(fBezierDistance);
750cdf0e10cSrcweir 								bDone = true;
751cdf0e10cSrcweir                             }
752cdf0e10cSrcweir                         }
753cdf0e10cSrcweir 
754cdf0e10cSrcweir 						if(!bDone)
755cdf0e10cSrcweir                         {
756cdf0e10cSrcweir 						    const double fRelativeInEdge(fDistance / fEdgeLength);
757cdf0e10cSrcweir     					    aRetval = interpolate(aRetval, aNextPoint, fRelativeInEdge);
758cdf0e10cSrcweir                         }
759cdf0e10cSrcweir                     }
760cdf0e10cSrcweir 				}
761cdf0e10cSrcweir 			}
762cdf0e10cSrcweir 
763cdf0e10cSrcweir 			return aRetval;
764cdf0e10cSrcweir 		}
765cdf0e10cSrcweir 
getPositionRelative(const B2DPolygon & rCandidate,double fDistance,double fLength)766cdf0e10cSrcweir 		B2DPoint getPositionRelative(const B2DPolygon& rCandidate, double fDistance, double fLength)
767cdf0e10cSrcweir 		{
768cdf0e10cSrcweir 			// get length if not given
769cdf0e10cSrcweir 			if(fTools::equalZero(fLength))
770cdf0e10cSrcweir 			{
771cdf0e10cSrcweir 				fLength = getLength(rCandidate);
772cdf0e10cSrcweir 			}
773cdf0e10cSrcweir 
774cdf0e10cSrcweir 			// multiply fDistance with real length to get absolute position and
775cdf0e10cSrcweir 			// use getPositionAbsolute
776cdf0e10cSrcweir 			return getPositionAbsolute(rCandidate, fDistance * fLength, fLength);
777cdf0e10cSrcweir 		}
778cdf0e10cSrcweir 
getSnippetAbsolute(const B2DPolygon & rCandidate,double fFrom,double fTo,double fLength)779cdf0e10cSrcweir 		B2DPolygon getSnippetAbsolute(const B2DPolygon& rCandidate, double fFrom, double fTo, double fLength)
780cdf0e10cSrcweir 		{
781cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
782cdf0e10cSrcweir 
783cdf0e10cSrcweir             if(nPointCount)
784cdf0e10cSrcweir             {
785cdf0e10cSrcweir 			    // get length if not given
786cdf0e10cSrcweir 			    if(fTools::equalZero(fLength))
787cdf0e10cSrcweir 			    {
788cdf0e10cSrcweir 				    fLength = getLength(rCandidate);
789cdf0e10cSrcweir 			    }
790cdf0e10cSrcweir 
791cdf0e10cSrcweir 			    // test and correct fFrom
792cdf0e10cSrcweir                 if(fTools::less(fFrom, 0.0))
793cdf0e10cSrcweir 			    {
794cdf0e10cSrcweir 				    fFrom = 0.0;
795cdf0e10cSrcweir 			    }
796cdf0e10cSrcweir 
797cdf0e10cSrcweir 			    // test and correct fTo
798cdf0e10cSrcweir                 if(fTools::more(fTo, fLength))
799cdf0e10cSrcweir 			    {
800cdf0e10cSrcweir 				    fTo = fLength;
801cdf0e10cSrcweir 			    }
802cdf0e10cSrcweir 
803cdf0e10cSrcweir 			    // test and correct relationship of fFrom, fTo
804cdf0e10cSrcweir                 if(fTools::more(fFrom, fTo))
805cdf0e10cSrcweir 			    {
806cdf0e10cSrcweir 				    fFrom = fTo = (fFrom + fTo) / 2.0;
807cdf0e10cSrcweir 			    }
808cdf0e10cSrcweir 
809cdf0e10cSrcweir                 if(fTools::equalZero(fFrom) && fTools::equal(fTo, fLength))
810cdf0e10cSrcweir 			    {
811cdf0e10cSrcweir 				    // no change, result is the whole polygon
812cdf0e10cSrcweir 				    return rCandidate;
813cdf0e10cSrcweir 			    }
814cdf0e10cSrcweir 			    else
815cdf0e10cSrcweir 			    {
816cdf0e10cSrcweir                     B2DPolygon aRetval;
817cdf0e10cSrcweir                     const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
818cdf0e10cSrcweir 				    double fPositionOfStart(0.0);
819cdf0e10cSrcweir 				    bool bStartDone(false);
820cdf0e10cSrcweir 				    bool bEndDone(false);
821cdf0e10cSrcweir 
822cdf0e10cSrcweir 				    for(sal_uInt32 a(0L); !(bStartDone && bEndDone) && a < nEdgeCount; a++)
823cdf0e10cSrcweir 				    {
824cdf0e10cSrcweir 					    const double fEdgeLength(getEdgeLength(rCandidate, a));
825cdf0e10cSrcweir 
826cdf0e10cSrcweir 					    if(!bStartDone)
827cdf0e10cSrcweir 					    {
828cdf0e10cSrcweir                             if(fTools::equalZero(fFrom))
829cdf0e10cSrcweir 						    {
830cdf0e10cSrcweir 							    aRetval.append(rCandidate.getB2DPoint(a));
831cdf0e10cSrcweir 
832cdf0e10cSrcweir                                 if(rCandidate.areControlPointsUsed())
833cdf0e10cSrcweir                                 {
834cdf0e10cSrcweir                                     aRetval.setNextControlPoint(aRetval.count() - 1, rCandidate.getNextControlPoint(a));
835cdf0e10cSrcweir                                 }
836cdf0e10cSrcweir 
837cdf0e10cSrcweir 							    bStartDone = true;
838cdf0e10cSrcweir 						    }
839cdf0e10cSrcweir                             else if(fTools::moreOrEqual(fFrom, fPositionOfStart) && fTools::less(fFrom, fPositionOfStart + fEdgeLength))
840cdf0e10cSrcweir 						    {
841cdf0e10cSrcweir 							    // calculate and add start point
842cdf0e10cSrcweir                                 if(fTools::equalZero(fEdgeLength))
843cdf0e10cSrcweir 							    {
844cdf0e10cSrcweir 								    aRetval.append(rCandidate.getB2DPoint(a));
845cdf0e10cSrcweir 
846cdf0e10cSrcweir                                     if(rCandidate.areControlPointsUsed())
847cdf0e10cSrcweir                                     {
848cdf0e10cSrcweir                                         aRetval.setNextControlPoint(aRetval.count() - 1, rCandidate.getNextControlPoint(a));
849cdf0e10cSrcweir                                     }
850cdf0e10cSrcweir 							    }
851cdf0e10cSrcweir                                 else
852cdf0e10cSrcweir 							    {
853cdf0e10cSrcweir                                     const sal_uInt32 nNextIndex((a + 1) % nPointCount);
854cdf0e10cSrcweir 					                const B2DPoint aStart(rCandidate.getB2DPoint(a));
855cdf0e10cSrcweir 					                const B2DPoint aEnd(rCandidate.getB2DPoint(nNextIndex));
856cdf0e10cSrcweir 									bool bDone(false);
857cdf0e10cSrcweir 
858cdf0e10cSrcweir                                     if(rCandidate.areControlPointsUsed())
859cdf0e10cSrcweir                                     {
860cdf0e10cSrcweir                                         const B2DCubicBezier aBezierSegment(
861cdf0e10cSrcweir                                             aStart, rCandidate.getNextControlPoint(a),
862cdf0e10cSrcweir                                             rCandidate.getPrevControlPoint(nNextIndex), aEnd);
863cdf0e10cSrcweir 
864cdf0e10cSrcweir                                         if(aBezierSegment.isBezier())
865cdf0e10cSrcweir                                         {
866cdf0e10cSrcweir                                             // use B2DCubicBezierHelper to bridge the non-linear gap between
867cdf0e10cSrcweir                                             // length and bezier distances
868cdf0e10cSrcweir                                             const B2DCubicBezierHelper aBezierSegmentHelper(aBezierSegment);
869cdf0e10cSrcweir                                             const double fBezierDistance(aBezierSegmentHelper.distanceToRelative(fFrom - fPositionOfStart));
870cdf0e10cSrcweir                                             B2DCubicBezier aRight;
871cdf0e10cSrcweir 
872cdf0e10cSrcweir                                             aBezierSegment.split(fBezierDistance, 0, &aRight);
873cdf0e10cSrcweir                                             aRetval.append(aRight.getStartPoint());
874cdf0e10cSrcweir                                             aRetval.setNextControlPoint(aRetval.count() - 1, aRight.getControlPointA());
875cdf0e10cSrcweir 											bDone = true;
876cdf0e10cSrcweir                                         }
877cdf0e10cSrcweir                                     }
878cdf0e10cSrcweir 
879cdf0e10cSrcweir 									if(!bDone)
880cdf0e10cSrcweir                                     {
881cdf0e10cSrcweir 	                                    const double fRelValue((fFrom - fPositionOfStart) / fEdgeLength);
882cdf0e10cSrcweir     								    aRetval.append(interpolate(aStart, aEnd, fRelValue));
883cdf0e10cSrcweir                                     }
884cdf0e10cSrcweir 							    }
885cdf0e10cSrcweir 
886cdf0e10cSrcweir 							    bStartDone = true;
887cdf0e10cSrcweir 
888cdf0e10cSrcweir 							    // if same point, end is done, too.
889cdf0e10cSrcweir 							    if(fFrom == fTo)
890cdf0e10cSrcweir 							    {
891cdf0e10cSrcweir 								    bEndDone = true;
892cdf0e10cSrcweir 							    }
893cdf0e10cSrcweir 						    }
894cdf0e10cSrcweir 					    }
895cdf0e10cSrcweir 
896cdf0e10cSrcweir                         if(!bEndDone && fTools::moreOrEqual(fTo, fPositionOfStart) && fTools::less(fTo, fPositionOfStart + fEdgeLength))
897cdf0e10cSrcweir 					    {
898cdf0e10cSrcweir 						    // calculate and add end point
899cdf0e10cSrcweir                             if(fTools::equalZero(fEdgeLength))
900cdf0e10cSrcweir 						    {
901cdf0e10cSrcweir                                 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
902cdf0e10cSrcweir 							    aRetval.append(rCandidate.getB2DPoint(nNextIndex));
903cdf0e10cSrcweir 
904cdf0e10cSrcweir                                 if(rCandidate.areControlPointsUsed())
905cdf0e10cSrcweir                                 {
906cdf0e10cSrcweir                                     aRetval.setPrevControlPoint(aRetval.count() - 1, rCandidate.getPrevControlPoint(nNextIndex));
907cdf0e10cSrcweir                                 }
908cdf0e10cSrcweir 						    }
909cdf0e10cSrcweir                             else
910cdf0e10cSrcweir                             {
911cdf0e10cSrcweir                                 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
912cdf0e10cSrcweir 				                const B2DPoint aStart(rCandidate.getB2DPoint(a));
913cdf0e10cSrcweir 				                const B2DPoint aEnd(rCandidate.getB2DPoint(nNextIndex));
914cdf0e10cSrcweir 								bool bDone(false);
915cdf0e10cSrcweir 
916cdf0e10cSrcweir                                 if(rCandidate.areControlPointsUsed())
917cdf0e10cSrcweir                                 {
918cdf0e10cSrcweir                                     const B2DCubicBezier aBezierSegment(
919cdf0e10cSrcweir                                         aStart, rCandidate.getNextControlPoint(a),
920cdf0e10cSrcweir                                         rCandidate.getPrevControlPoint(nNextIndex), aEnd);
921cdf0e10cSrcweir 
922cdf0e10cSrcweir                                     if(aBezierSegment.isBezier())
923cdf0e10cSrcweir                                     {
924cdf0e10cSrcweir                                         // use B2DCubicBezierHelper to bridge the non-linear gap between
925cdf0e10cSrcweir                                         // length and bezier distances
926cdf0e10cSrcweir                                         const B2DCubicBezierHelper aBezierSegmentHelper(aBezierSegment);
927cdf0e10cSrcweir                                         const double fBezierDistance(aBezierSegmentHelper.distanceToRelative(fTo - fPositionOfStart));
928cdf0e10cSrcweir                                         B2DCubicBezier aLeft;
929cdf0e10cSrcweir 
930cdf0e10cSrcweir                                         aBezierSegment.split(fBezierDistance, &aLeft, 0);
931cdf0e10cSrcweir                                         aRetval.append(aLeft.getEndPoint());
932cdf0e10cSrcweir                                         aRetval.setPrevControlPoint(aRetval.count() - 1, aLeft.getControlPointB());
933cdf0e10cSrcweir 										bDone = true;
934cdf0e10cSrcweir                                     }
935cdf0e10cSrcweir                                 }
936cdf0e10cSrcweir 
937cdf0e10cSrcweir                                 if(!bDone)
938cdf0e10cSrcweir                                 {
939cdf0e10cSrcweir 	                                const double fRelValue((fTo - fPositionOfStart) / fEdgeLength);
940cdf0e10cSrcweir 								    aRetval.append(interpolate(aStart, aEnd, fRelValue));
941cdf0e10cSrcweir                                 }
942cdf0e10cSrcweir 						    }
943cdf0e10cSrcweir 
944cdf0e10cSrcweir 						    bEndDone = true;
945cdf0e10cSrcweir 					    }
946cdf0e10cSrcweir 
947cdf0e10cSrcweir 					    if(!bEndDone)
948cdf0e10cSrcweir 					    {
949cdf0e10cSrcweir 						    if(bStartDone)
950cdf0e10cSrcweir 						    {
951cdf0e10cSrcweir 							    // add segments end point
952cdf0e10cSrcweir                                 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
953cdf0e10cSrcweir 							    aRetval.append(rCandidate.getB2DPoint(nNextIndex));
954cdf0e10cSrcweir 
955cdf0e10cSrcweir                                 if(rCandidate.areControlPointsUsed())
956cdf0e10cSrcweir                                 {
957cdf0e10cSrcweir                                     aRetval.setPrevControlPoint(aRetval.count() - 1, rCandidate.getPrevControlPoint(nNextIndex));
958cdf0e10cSrcweir                                     aRetval.setNextControlPoint(aRetval.count() - 1, rCandidate.getNextControlPoint(nNextIndex));
959cdf0e10cSrcweir                                 }
960cdf0e10cSrcweir 						    }
961cdf0e10cSrcweir 
962cdf0e10cSrcweir 						    // increment fPositionOfStart
963cdf0e10cSrcweir 						    fPositionOfStart += fEdgeLength;
964cdf0e10cSrcweir 					    }
965cdf0e10cSrcweir 				    }
966cdf0e10cSrcweir     			    return aRetval;
967cdf0e10cSrcweir 			    }
968cdf0e10cSrcweir             }
969cdf0e10cSrcweir             else
970cdf0e10cSrcweir             {
971cdf0e10cSrcweir                 return rCandidate;
972cdf0e10cSrcweir             }
973cdf0e10cSrcweir 		}
974cdf0e10cSrcweir 
getSnippetRelative(const B2DPolygon & rCandidate,double fFrom,double fTo,double fLength)975cdf0e10cSrcweir 		B2DPolygon getSnippetRelative(const B2DPolygon& rCandidate, double fFrom, double fTo, double fLength)
976cdf0e10cSrcweir 		{
977cdf0e10cSrcweir 			// get length if not given
978cdf0e10cSrcweir 			if(fTools::equalZero(fLength))
979cdf0e10cSrcweir 			{
980cdf0e10cSrcweir 				fLength = getLength(rCandidate);
981cdf0e10cSrcweir 			}
982cdf0e10cSrcweir 
983cdf0e10cSrcweir 			// multiply distances with real length to get absolute position and
984cdf0e10cSrcweir 			// use getSnippetAbsolute
985cdf0e10cSrcweir 			return getSnippetAbsolute(rCandidate, fFrom * fLength, fTo * fLength, fLength);
986cdf0e10cSrcweir 		}
987cdf0e10cSrcweir 
findCut(const B2DPolygon & rCandidate,sal_uInt32 nIndex1,sal_uInt32 nIndex2,CutFlagValue aCutFlags,double * pCut1,double * pCut2)988cdf0e10cSrcweir 		CutFlagValue findCut(
989cdf0e10cSrcweir 			const B2DPolygon& rCandidate,
990cdf0e10cSrcweir 			sal_uInt32 nIndex1, sal_uInt32 nIndex2,
991cdf0e10cSrcweir 			CutFlagValue aCutFlags,
992cdf0e10cSrcweir 			double* pCut1, double* pCut2)
993cdf0e10cSrcweir 		{
994cdf0e10cSrcweir 			CutFlagValue aRetval(CUTFLAG_NONE);
995cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
996cdf0e10cSrcweir 
997cdf0e10cSrcweir 			if(nIndex1 < nPointCount && nIndex2 < nPointCount && nIndex1 != nIndex2)
998cdf0e10cSrcweir 			{
999cdf0e10cSrcweir 				sal_uInt32 nEnd1(getIndexOfSuccessor(nIndex1, rCandidate));
1000cdf0e10cSrcweir 				sal_uInt32 nEnd2(getIndexOfSuccessor(nIndex2, rCandidate));
1001cdf0e10cSrcweir 
1002cdf0e10cSrcweir 				const B2DPoint aStart1(rCandidate.getB2DPoint(nIndex1));
1003cdf0e10cSrcweir 				const B2DPoint aEnd1(rCandidate.getB2DPoint(nEnd1));
1004cdf0e10cSrcweir 				const B2DVector aVector1(aEnd1 - aStart1);
1005cdf0e10cSrcweir 
1006cdf0e10cSrcweir 				const B2DPoint aStart2(rCandidate.getB2DPoint(nIndex2));
1007cdf0e10cSrcweir 				const B2DPoint aEnd2(rCandidate.getB2DPoint(nEnd2));
1008cdf0e10cSrcweir 				const B2DVector aVector2(aEnd2 - aStart2);
1009cdf0e10cSrcweir 
1010cdf0e10cSrcweir 				aRetval = findCut(
1011cdf0e10cSrcweir 					aStart1, aVector1, aStart2, aVector2,
1012cdf0e10cSrcweir 					aCutFlags, pCut1, pCut2);
1013cdf0e10cSrcweir 			}
1014cdf0e10cSrcweir 
1015cdf0e10cSrcweir 			return aRetval;
1016cdf0e10cSrcweir 		}
1017cdf0e10cSrcweir 
findCut(const B2DPolygon & rCandidate1,sal_uInt32 nIndex1,const B2DPolygon & rCandidate2,sal_uInt32 nIndex2,CutFlagValue aCutFlags,double * pCut1,double * pCut2)1018cdf0e10cSrcweir 		CutFlagValue findCut(
1019cdf0e10cSrcweir 			const B2DPolygon& rCandidate1, sal_uInt32 nIndex1,
1020cdf0e10cSrcweir 			const B2DPolygon& rCandidate2, sal_uInt32 nIndex2,
1021cdf0e10cSrcweir 			CutFlagValue aCutFlags,
1022cdf0e10cSrcweir 			double* pCut1, double* pCut2)
1023cdf0e10cSrcweir 		{
1024cdf0e10cSrcweir 			CutFlagValue aRetval(CUTFLAG_NONE);
1025cdf0e10cSrcweir 			const sal_uInt32 nPointCount1(rCandidate1.count());
1026cdf0e10cSrcweir 			const sal_uInt32 nPointCount2(rCandidate2.count());
1027cdf0e10cSrcweir 
1028cdf0e10cSrcweir 			if(nIndex1 < nPointCount1 && nIndex2 < nPointCount2)
1029cdf0e10cSrcweir 			{
1030cdf0e10cSrcweir 				sal_uInt32 nEnd1(getIndexOfSuccessor(nIndex1, rCandidate1));
1031cdf0e10cSrcweir 				sal_uInt32 nEnd2(getIndexOfSuccessor(nIndex2, rCandidate2));
1032cdf0e10cSrcweir 
1033cdf0e10cSrcweir 				const B2DPoint aStart1(rCandidate1.getB2DPoint(nIndex1));
1034cdf0e10cSrcweir 				const B2DPoint aEnd1(rCandidate1.getB2DPoint(nEnd1));
1035cdf0e10cSrcweir 				const B2DVector aVector1(aEnd1 - aStart1);
1036cdf0e10cSrcweir 
1037cdf0e10cSrcweir 				const B2DPoint aStart2(rCandidate2.getB2DPoint(nIndex2));
1038cdf0e10cSrcweir 				const B2DPoint aEnd2(rCandidate2.getB2DPoint(nEnd2));
1039cdf0e10cSrcweir 				const B2DVector aVector2(aEnd2 - aStart2);
1040cdf0e10cSrcweir 
1041cdf0e10cSrcweir 				aRetval = findCut(
1042cdf0e10cSrcweir 					aStart1, aVector1, aStart2, aVector2,
1043cdf0e10cSrcweir 					aCutFlags, pCut1, pCut2);
1044cdf0e10cSrcweir 			}
1045cdf0e10cSrcweir 
1046cdf0e10cSrcweir 			return aRetval;
1047cdf0e10cSrcweir 		}
1048cdf0e10cSrcweir 
findCut(const B2DPoint & rEdge1Start,const B2DVector & rEdge1Delta,const B2DPoint & rEdge2Start,const B2DVector & rEdge2Delta,CutFlagValue aCutFlags,double * pCut1,double * pCut2)1049cdf0e10cSrcweir 		CutFlagValue findCut(
1050cdf0e10cSrcweir 			const B2DPoint& rEdge1Start, const B2DVector& rEdge1Delta,
1051cdf0e10cSrcweir 			const B2DPoint& rEdge2Start, const B2DVector& rEdge2Delta,
1052cdf0e10cSrcweir 			CutFlagValue aCutFlags,
1053cdf0e10cSrcweir 			double* pCut1, double* pCut2)
1054cdf0e10cSrcweir 		{
1055cdf0e10cSrcweir 			CutFlagValue aRetval(CUTFLAG_NONE);
1056cdf0e10cSrcweir 			double fCut1(0.0);
1057cdf0e10cSrcweir 			double fCut2(0.0);
1058cdf0e10cSrcweir 			bool bFinished(!((bool)(aCutFlags & CUTFLAG_ALL)));
1059cdf0e10cSrcweir 
1060cdf0e10cSrcweir 			// test for same points?
1061cdf0e10cSrcweir 			if(!bFinished
1062cdf0e10cSrcweir 				&& (aCutFlags & (CUTFLAG_START1|CUTFLAG_END1))
1063cdf0e10cSrcweir 				&& (aCutFlags & (CUTFLAG_START2|CUTFLAG_END2)))
1064cdf0e10cSrcweir 			{
1065cdf0e10cSrcweir 				// same startpoint?
1066cdf0e10cSrcweir 				if(!bFinished && (aCutFlags & (CUTFLAG_START1|CUTFLAG_START2)) == (CUTFLAG_START1|CUTFLAG_START2))
1067cdf0e10cSrcweir 				{
1068cdf0e10cSrcweir 					if(rEdge1Start.equal(rEdge2Start))
1069cdf0e10cSrcweir 					{
1070cdf0e10cSrcweir 						bFinished = true;
1071cdf0e10cSrcweir 						aRetval = (CUTFLAG_START1|CUTFLAG_START2);
1072cdf0e10cSrcweir 					}
1073cdf0e10cSrcweir 				}
1074cdf0e10cSrcweir 
1075cdf0e10cSrcweir 				// same endpoint?
1076cdf0e10cSrcweir 				if(!bFinished && (aCutFlags & (CUTFLAG_END1|CUTFLAG_END2)) == (CUTFLAG_END1|CUTFLAG_END2))
1077cdf0e10cSrcweir 				{
1078cdf0e10cSrcweir 					const B2DPoint aEnd1(rEdge1Start + rEdge1Delta);
1079cdf0e10cSrcweir 					const B2DPoint aEnd2(rEdge2Start + rEdge2Delta);
1080cdf0e10cSrcweir 
1081cdf0e10cSrcweir 					if(aEnd1.equal(aEnd2))
1082cdf0e10cSrcweir 					{
1083cdf0e10cSrcweir 						bFinished = true;
1084cdf0e10cSrcweir 						aRetval = (CUTFLAG_END1|CUTFLAG_END2);
1085cdf0e10cSrcweir 						fCut1 = fCut2 = 1.0;
1086cdf0e10cSrcweir 					}
1087cdf0e10cSrcweir 				}
1088cdf0e10cSrcweir 
1089cdf0e10cSrcweir 				// startpoint1 == endpoint2?
1090cdf0e10cSrcweir 				if(!bFinished && (aCutFlags & (CUTFLAG_START1|CUTFLAG_END2)) == (CUTFLAG_START1|CUTFLAG_END2))
1091cdf0e10cSrcweir 				{
1092cdf0e10cSrcweir 					const B2DPoint aEnd2(rEdge2Start + rEdge2Delta);
1093cdf0e10cSrcweir 
1094cdf0e10cSrcweir 					if(rEdge1Start.equal(aEnd2))
1095cdf0e10cSrcweir 					{
1096cdf0e10cSrcweir 						bFinished = true;
1097cdf0e10cSrcweir 						aRetval = (CUTFLAG_START1|CUTFLAG_END2);
1098cdf0e10cSrcweir 						fCut1 = 0.0;
1099cdf0e10cSrcweir 						fCut2 = 1.0;
1100cdf0e10cSrcweir 					}
1101cdf0e10cSrcweir 				}
1102cdf0e10cSrcweir 
1103cdf0e10cSrcweir 				// startpoint2 == endpoint1?
1104cdf0e10cSrcweir 				if(!bFinished&& (aCutFlags & (CUTFLAG_START2|CUTFLAG_END1)) == (CUTFLAG_START2|CUTFLAG_END1))
1105cdf0e10cSrcweir 				{
1106cdf0e10cSrcweir 					const B2DPoint aEnd1(rEdge1Start + rEdge1Delta);
1107cdf0e10cSrcweir 
1108cdf0e10cSrcweir 					if(rEdge2Start.equal(aEnd1))
1109cdf0e10cSrcweir 					{
1110cdf0e10cSrcweir 						bFinished = true;
1111cdf0e10cSrcweir 						aRetval = (CUTFLAG_START2|CUTFLAG_END1);
1112cdf0e10cSrcweir 						fCut1 = 1.0;
1113cdf0e10cSrcweir 						fCut2 = 0.0;
1114cdf0e10cSrcweir 					}
1115cdf0e10cSrcweir 				}
1116cdf0e10cSrcweir 			}
1117cdf0e10cSrcweir 
1118cdf0e10cSrcweir 			if(!bFinished && (aCutFlags & CUTFLAG_LINE))
1119cdf0e10cSrcweir 			{
1120cdf0e10cSrcweir 				if(!bFinished && (aCutFlags & CUTFLAG_START1))
1121cdf0e10cSrcweir 				{
1122cdf0e10cSrcweir 					// start1 on line 2 ?
1123cdf0e10cSrcweir 					if(isPointOnEdge(rEdge1Start, rEdge2Start, rEdge2Delta, &fCut2))
1124cdf0e10cSrcweir 					{
1125cdf0e10cSrcweir 						bFinished = true;
1126cdf0e10cSrcweir 						aRetval = (CUTFLAG_LINE|CUTFLAG_START1);
1127cdf0e10cSrcweir 					}
1128cdf0e10cSrcweir 				}
1129cdf0e10cSrcweir 
1130cdf0e10cSrcweir 				if(!bFinished && (aCutFlags & CUTFLAG_START2))
1131cdf0e10cSrcweir 				{
1132cdf0e10cSrcweir 					// start2 on line 1 ?
1133cdf0e10cSrcweir 					if(isPointOnEdge(rEdge2Start, rEdge1Start, rEdge1Delta, &fCut1))
1134cdf0e10cSrcweir 					{
1135cdf0e10cSrcweir 						bFinished = true;
1136cdf0e10cSrcweir 						aRetval = (CUTFLAG_LINE|CUTFLAG_START2);
1137cdf0e10cSrcweir 					}
1138cdf0e10cSrcweir 				}
1139cdf0e10cSrcweir 
1140cdf0e10cSrcweir 				if(!bFinished && (aCutFlags & CUTFLAG_END1))
1141cdf0e10cSrcweir 				{
1142cdf0e10cSrcweir 					// end1 on line 2 ?
1143cdf0e10cSrcweir 					const B2DPoint aEnd1(rEdge1Start + rEdge1Delta);
1144cdf0e10cSrcweir 
1145cdf0e10cSrcweir 					if(isPointOnEdge(aEnd1, rEdge2Start, rEdge2Delta, &fCut2))
1146cdf0e10cSrcweir 					{
1147cdf0e10cSrcweir 						bFinished = true;
1148cdf0e10cSrcweir 						aRetval = (CUTFLAG_LINE|CUTFLAG_END1);
1149cdf0e10cSrcweir 					}
1150cdf0e10cSrcweir 				}
1151cdf0e10cSrcweir 
1152cdf0e10cSrcweir 				if(!bFinished && (aCutFlags & CUTFLAG_END2))
1153cdf0e10cSrcweir 				{
1154cdf0e10cSrcweir 					// end2 on line 1 ?
1155cdf0e10cSrcweir 					const B2DPoint aEnd2(rEdge2Start + rEdge2Delta);
1156cdf0e10cSrcweir 
1157cdf0e10cSrcweir 					if(isPointOnEdge(aEnd2, rEdge1Start, rEdge1Delta, &fCut1))
1158cdf0e10cSrcweir 					{
1159cdf0e10cSrcweir 						bFinished = true;
1160cdf0e10cSrcweir 						aRetval = (CUTFLAG_LINE|CUTFLAG_END2);
1161cdf0e10cSrcweir 					}
1162cdf0e10cSrcweir 				}
1163cdf0e10cSrcweir 
1164cdf0e10cSrcweir 				if(!bFinished)
1165cdf0e10cSrcweir 				{
1166cdf0e10cSrcweir 					// cut in line1, line2 ?
1167cdf0e10cSrcweir 					fCut1 = (rEdge1Delta.getX() * rEdge2Delta.getY()) - (rEdge1Delta.getY() * rEdge2Delta.getX());
1168cdf0e10cSrcweir 
1169cdf0e10cSrcweir 					if(!fTools::equalZero(fCut1))
1170cdf0e10cSrcweir 					{
1171cdf0e10cSrcweir 						fCut1 = (rEdge2Delta.getY() * (rEdge2Start.getX() - rEdge1Start.getX())
1172cdf0e10cSrcweir 							+ rEdge2Delta.getX() * (rEdge1Start.getY() - rEdge2Start.getY())) / fCut1;
1173cdf0e10cSrcweir 
1174cdf0e10cSrcweir 						const double fZero(0.0);
1175cdf0e10cSrcweir 						const double fOne(1.0);
1176cdf0e10cSrcweir 
1177cdf0e10cSrcweir 						// inside parameter range edge1 AND fCut2 is calcable
1178cdf0e10cSrcweir 						if(fTools::more(fCut1, fZero) && fTools::less(fCut1, fOne)
1179cdf0e10cSrcweir 							&& (!fTools::equalZero(rEdge2Delta.getX()) || !fTools::equalZero(rEdge2Delta.getY())))
1180cdf0e10cSrcweir 						{
1181cdf0e10cSrcweir 							// take the mopre precise calculation of the two possible
1182cdf0e10cSrcweir 							if(fabs(rEdge2Delta.getX()) > fabs(rEdge2Delta.getY()))
1183cdf0e10cSrcweir 							{
1184cdf0e10cSrcweir 								fCut2 = (rEdge1Start.getX() + fCut1
1185cdf0e10cSrcweir 									* rEdge1Delta.getX() - rEdge2Start.getX()) / rEdge2Delta.getX();
1186cdf0e10cSrcweir 							}
1187cdf0e10cSrcweir 							else
1188cdf0e10cSrcweir 							{
1189cdf0e10cSrcweir 								fCut2 = (rEdge1Start.getY() + fCut1
1190cdf0e10cSrcweir 									* rEdge1Delta.getY() - rEdge2Start.getY()) / rEdge2Delta.getY();
1191cdf0e10cSrcweir 							}
1192cdf0e10cSrcweir 
1193cdf0e10cSrcweir 							// inside parameter range edge2, too
1194cdf0e10cSrcweir 							if(fTools::more(fCut2, fZero) && fTools::less(fCut2, fOne))
1195cdf0e10cSrcweir 							{
1196cdf0e10cSrcweir 								bFinished = true;
1197cdf0e10cSrcweir 								aRetval = CUTFLAG_LINE;
1198cdf0e10cSrcweir 							}
1199cdf0e10cSrcweir 						}
1200cdf0e10cSrcweir 					}
1201cdf0e10cSrcweir 				}
1202cdf0e10cSrcweir 			}
1203cdf0e10cSrcweir 
1204cdf0e10cSrcweir 			// copy values if wanted
1205cdf0e10cSrcweir 			if(pCut1)
1206cdf0e10cSrcweir 			{
1207cdf0e10cSrcweir 				*pCut1 = fCut1;
1208cdf0e10cSrcweir 			}
1209cdf0e10cSrcweir 
1210cdf0e10cSrcweir 			if(pCut2)
1211cdf0e10cSrcweir 			{
1212cdf0e10cSrcweir 				*pCut2 = fCut2;
1213cdf0e10cSrcweir 			}
1214cdf0e10cSrcweir 
1215cdf0e10cSrcweir 			return aRetval;
1216cdf0e10cSrcweir 		}
1217cdf0e10cSrcweir 
isPointOnEdge(const B2DPoint & rPoint,const B2DPoint & rEdgeStart,const B2DVector & rEdgeDelta,double * pCut)1218cdf0e10cSrcweir 		bool isPointOnEdge(
1219cdf0e10cSrcweir 			const B2DPoint& rPoint,
1220cdf0e10cSrcweir 			const B2DPoint& rEdgeStart,
1221cdf0e10cSrcweir 			const B2DVector& rEdgeDelta,
1222cdf0e10cSrcweir 			double* pCut)
1223cdf0e10cSrcweir 		{
1224cdf0e10cSrcweir 			bool bDeltaXIsZero(fTools::equalZero(rEdgeDelta.getX()));
1225cdf0e10cSrcweir 			bool bDeltaYIsZero(fTools::equalZero(rEdgeDelta.getY()));
1226cdf0e10cSrcweir 			const double fZero(0.0);
1227cdf0e10cSrcweir 			const double fOne(1.0);
1228cdf0e10cSrcweir 
1229cdf0e10cSrcweir 			if(bDeltaXIsZero && bDeltaYIsZero)
1230cdf0e10cSrcweir 			{
1231cdf0e10cSrcweir 				// no line, just a point
1232cdf0e10cSrcweir 				return false;
1233cdf0e10cSrcweir 			}
1234cdf0e10cSrcweir 			else if(bDeltaXIsZero)
1235cdf0e10cSrcweir 			{
1236cdf0e10cSrcweir 				// vertical line
1237cdf0e10cSrcweir 				if(fTools::equal(rPoint.getX(), rEdgeStart.getX()))
1238cdf0e10cSrcweir 				{
1239cdf0e10cSrcweir 					double fValue = (rPoint.getY() - rEdgeStart.getY()) / rEdgeDelta.getY();
1240cdf0e10cSrcweir 
1241cdf0e10cSrcweir 					if(fTools::more(fValue, fZero) && fTools::less(fValue, fOne))
1242cdf0e10cSrcweir 					{
1243cdf0e10cSrcweir 						if(pCut)
1244cdf0e10cSrcweir 						{
1245cdf0e10cSrcweir 							*pCut = fValue;
1246cdf0e10cSrcweir 						}
1247cdf0e10cSrcweir 
1248cdf0e10cSrcweir 						return true;
1249cdf0e10cSrcweir 					}
1250cdf0e10cSrcweir 				}
1251cdf0e10cSrcweir 			}
1252cdf0e10cSrcweir 			else if(bDeltaYIsZero)
1253cdf0e10cSrcweir 			{
1254cdf0e10cSrcweir 				// horizontal line
1255cdf0e10cSrcweir 				if(fTools::equal(rPoint.getY(), rEdgeStart.getY()))
1256cdf0e10cSrcweir 				{
1257cdf0e10cSrcweir 					double fValue = (rPoint.getX() - rEdgeStart.getX()) / rEdgeDelta.getX();
1258cdf0e10cSrcweir 
1259cdf0e10cSrcweir 					if(fTools::more(fValue, fZero) && fTools::less(fValue, fOne))
1260cdf0e10cSrcweir 					{
1261cdf0e10cSrcweir 						if(pCut)
1262cdf0e10cSrcweir 						{
1263cdf0e10cSrcweir 							*pCut = fValue;
1264cdf0e10cSrcweir 						}
1265cdf0e10cSrcweir 
1266cdf0e10cSrcweir 						return true;
1267cdf0e10cSrcweir 					}
1268cdf0e10cSrcweir 				}
1269cdf0e10cSrcweir 			}
1270cdf0e10cSrcweir 			else
1271cdf0e10cSrcweir 			{
1272cdf0e10cSrcweir 				// any angle line
1273cdf0e10cSrcweir 				double fTOne = (rPoint.getX() - rEdgeStart.getX()) / rEdgeDelta.getX();
1274cdf0e10cSrcweir 				double fTTwo = (rPoint.getY() - rEdgeStart.getY()) / rEdgeDelta.getY();
1275cdf0e10cSrcweir 
1276cdf0e10cSrcweir 				if(fTools::equal(fTOne, fTTwo))
1277cdf0e10cSrcweir 				{
1278cdf0e10cSrcweir 					// same parameter representation, point is on line. Take
1279cdf0e10cSrcweir 					// middle value for better results
1280cdf0e10cSrcweir 					double fValue = (fTOne + fTTwo) / 2.0;
1281cdf0e10cSrcweir 
1282cdf0e10cSrcweir 					if(fTools::more(fValue, fZero) && fTools::less(fValue, fOne))
1283cdf0e10cSrcweir 					{
1284cdf0e10cSrcweir 						// point is inside line bounds, too
1285cdf0e10cSrcweir 						if(pCut)
1286cdf0e10cSrcweir 						{
1287cdf0e10cSrcweir 							*pCut = fValue;
1288cdf0e10cSrcweir 						}
1289cdf0e10cSrcweir 
1290cdf0e10cSrcweir 						return true;
1291cdf0e10cSrcweir 					}
1292cdf0e10cSrcweir 				}
1293cdf0e10cSrcweir 			}
1294cdf0e10cSrcweir 
1295cdf0e10cSrcweir 			return false;
1296cdf0e10cSrcweir 		}
1297cdf0e10cSrcweir 
applyLineDashing(const B2DPolygon & rCandidate,const::std::vector<double> & rDotDashArray,B2DPolyPolygon * pLineTarget,B2DPolyPolygon * pGapTarget,double fDotDashLength)1298cdf0e10cSrcweir 		void applyLineDashing(const B2DPolygon& rCandidate, const ::std::vector<double>& rDotDashArray, B2DPolyPolygon* pLineTarget, B2DPolyPolygon* pGapTarget, double fDotDashLength)
1299cdf0e10cSrcweir         {
1300cdf0e10cSrcweir             const sal_uInt32 nPointCount(rCandidate.count());
1301cdf0e10cSrcweir             const sal_uInt32 nDotDashCount(rDotDashArray.size());
1302cdf0e10cSrcweir 
1303cdf0e10cSrcweir 			if(fTools::lessOrEqual(fDotDashLength, 0.0))
1304cdf0e10cSrcweir             {
1305cdf0e10cSrcweir                 fDotDashLength = ::std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
1306cdf0e10cSrcweir             }
1307cdf0e10cSrcweir 
1308cdf0e10cSrcweir 			if(fTools::more(fDotDashLength, 0.0) && (pLineTarget || pGapTarget) && nPointCount)
1309cdf0e10cSrcweir             {
1310cdf0e10cSrcweir 				// clear targets
1311cdf0e10cSrcweir 				if(pLineTarget)
1312cdf0e10cSrcweir 				{
1313cdf0e10cSrcweir 					pLineTarget->clear();
1314cdf0e10cSrcweir 				}
1315cdf0e10cSrcweir 
1316cdf0e10cSrcweir 				if(pGapTarget)
1317cdf0e10cSrcweir 				{
1318cdf0e10cSrcweir 					pGapTarget->clear();
1319cdf0e10cSrcweir 				}
1320cdf0e10cSrcweir 
1321cdf0e10cSrcweir                 // prepare current edge's start
1322cdf0e10cSrcweir 				B2DCubicBezier aCurrentEdge;
1323cdf0e10cSrcweir                 const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
1324cdf0e10cSrcweir                 aCurrentEdge.setStartPoint(rCandidate.getB2DPoint(0));
1325cdf0e10cSrcweir 
1326cdf0e10cSrcweir                 // prepare DotDashArray iteration and the line/gap switching bool
1327cdf0e10cSrcweir                 sal_uInt32 nDotDashIndex(0);
1328cdf0e10cSrcweir                 bool bIsLine(true);
1329cdf0e10cSrcweir                 double fDotDashMovingLength(rDotDashArray[0]);
1330cdf0e10cSrcweir 				B2DPolygon aSnippet;
1331cdf0e10cSrcweir 
1332cdf0e10cSrcweir 				// iterate over all edges
1333cdf0e10cSrcweir                 for(sal_uInt32 a(0); a < nEdgeCount; a++)
1334cdf0e10cSrcweir                 {
1335cdf0e10cSrcweir                     // update current edge (fill in C1, C2 and end point)
1336cdf0e10cSrcweir 					double fLastDotDashMovingLength(0.0);
1337cdf0e10cSrcweir                     const sal_uInt32 nNextIndex((a + 1) % nPointCount);
1338cdf0e10cSrcweir                     aCurrentEdge.setControlPointA(rCandidate.getNextControlPoint(a));
1339cdf0e10cSrcweir                     aCurrentEdge.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
1340cdf0e10cSrcweir                     aCurrentEdge.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
1341cdf0e10cSrcweir 
1342cdf0e10cSrcweir 					// check if we have a trivial bezier segment -> possible fallback to edge
1343cdf0e10cSrcweir 					aCurrentEdge.testAndSolveTrivialBezier();
1344cdf0e10cSrcweir 
1345cdf0e10cSrcweir 					if(aCurrentEdge.isBezier())
1346cdf0e10cSrcweir 					{
1347cdf0e10cSrcweir 						// bezier segment
1348cdf0e10cSrcweir 						const B2DCubicBezierHelper aCubicBezierHelper(aCurrentEdge);
1349cdf0e10cSrcweir 						const double fEdgeLength(aCubicBezierHelper.getLength());
1350cdf0e10cSrcweir 
1351cdf0e10cSrcweir 						if(!fTools::equalZero(fEdgeLength))
1352cdf0e10cSrcweir 						{
1353cdf0e10cSrcweir 							while(fTools::less(fDotDashMovingLength, fEdgeLength))
1354cdf0e10cSrcweir 							{
1355cdf0e10cSrcweir 								// new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
1356cdf0e10cSrcweir 								const bool bHandleLine(bIsLine && pLineTarget);
1357cdf0e10cSrcweir 								const bool bHandleGap(!bIsLine && pGapTarget);
1358cdf0e10cSrcweir 
1359cdf0e10cSrcweir 								if(bHandleLine || bHandleGap)
1360cdf0e10cSrcweir 								{
1361cdf0e10cSrcweir 									const double fBezierSplitStart(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
1362cdf0e10cSrcweir 									const double fBezierSplitEnd(aCubicBezierHelper.distanceToRelative(fDotDashMovingLength));
1363cdf0e10cSrcweir 									B2DCubicBezier aBezierSnippet(aCurrentEdge.snippet(fBezierSplitStart, fBezierSplitEnd));
1364cdf0e10cSrcweir 
1365cdf0e10cSrcweir 									if(!aSnippet.count())
1366cdf0e10cSrcweir 									{
1367cdf0e10cSrcweir 										aSnippet.append(aBezierSnippet.getStartPoint());
1368cdf0e10cSrcweir 									}
1369cdf0e10cSrcweir 
1370cdf0e10cSrcweir 									aSnippet.appendBezierSegment(aBezierSnippet.getControlPointA(), aBezierSnippet.getControlPointB(), aBezierSnippet.getEndPoint());
1371cdf0e10cSrcweir 
1372cdf0e10cSrcweir 									if(bHandleLine)
1373cdf0e10cSrcweir 									{
1374cdf0e10cSrcweir 										pLineTarget->append(aSnippet);
1375cdf0e10cSrcweir 									}
1376cdf0e10cSrcweir 									else
1377cdf0e10cSrcweir 									{
1378cdf0e10cSrcweir 										pGapTarget->append(aSnippet);
1379cdf0e10cSrcweir 									}
1380cdf0e10cSrcweir 
1381cdf0e10cSrcweir 									aSnippet.clear();
1382cdf0e10cSrcweir 								}
1383cdf0e10cSrcweir 
1384cdf0e10cSrcweir 								// prepare next DotDashArray step and flip line/gap flag
1385cdf0e10cSrcweir 								fLastDotDashMovingLength = fDotDashMovingLength;
1386cdf0e10cSrcweir 								fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
1387cdf0e10cSrcweir 								bIsLine = !bIsLine;
1388cdf0e10cSrcweir 							}
1389cdf0e10cSrcweir 
1390cdf0e10cSrcweir 							// append closing snippet [fLastDotDashMovingLength, fEdgeLength]
1391cdf0e10cSrcweir 							const bool bHandleLine(bIsLine && pLineTarget);
1392cdf0e10cSrcweir 							const bool bHandleGap(!bIsLine && pGapTarget);
1393cdf0e10cSrcweir 
1394cdf0e10cSrcweir 							if(bHandleLine || bHandleGap)
1395cdf0e10cSrcweir 							{
1396cdf0e10cSrcweir 								B2DCubicBezier aRight;
1397cdf0e10cSrcweir 								const double fBezierSplit(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
1398cdf0e10cSrcweir 
1399cdf0e10cSrcweir 								aCurrentEdge.split(fBezierSplit, 0, &aRight);
1400cdf0e10cSrcweir 
1401cdf0e10cSrcweir 								if(!aSnippet.count())
1402cdf0e10cSrcweir 								{
1403cdf0e10cSrcweir 									aSnippet.append(aRight.getStartPoint());
1404cdf0e10cSrcweir 								}
1405cdf0e10cSrcweir 
1406cdf0e10cSrcweir 								aSnippet.appendBezierSegment(aRight.getControlPointA(), aRight.getControlPointB(), aRight.getEndPoint());
1407cdf0e10cSrcweir 							}
1408cdf0e10cSrcweir 
1409cdf0e10cSrcweir 							// prepare move to next edge
1410cdf0e10cSrcweir 							fDotDashMovingLength -= fEdgeLength;
1411cdf0e10cSrcweir 						}
1412cdf0e10cSrcweir 					}
1413cdf0e10cSrcweir 					else
1414cdf0e10cSrcweir 					{
1415cdf0e10cSrcweir 						// simple edge
1416cdf0e10cSrcweir 						const double fEdgeLength(aCurrentEdge.getEdgeLength());
1417cdf0e10cSrcweir 
1418cdf0e10cSrcweir 						if(!fTools::equalZero(fEdgeLength))
1419cdf0e10cSrcweir 						{
1420cdf0e10cSrcweir 							while(fTools::less(fDotDashMovingLength, fEdgeLength))
1421cdf0e10cSrcweir 							{
1422cdf0e10cSrcweir 								// new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
1423cdf0e10cSrcweir 								const bool bHandleLine(bIsLine && pLineTarget);
1424cdf0e10cSrcweir 								const bool bHandleGap(!bIsLine && pGapTarget);
1425cdf0e10cSrcweir 
1426cdf0e10cSrcweir 								if(bHandleLine || bHandleGap)
1427cdf0e10cSrcweir 								{
1428cdf0e10cSrcweir 									if(!aSnippet.count())
1429cdf0e10cSrcweir 									{
1430cdf0e10cSrcweir 										aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fLastDotDashMovingLength / fEdgeLength));
1431cdf0e10cSrcweir 									}
1432cdf0e10cSrcweir 
1433cdf0e10cSrcweir 									aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fDotDashMovingLength / fEdgeLength));
1434cdf0e10cSrcweir 
1435cdf0e10cSrcweir 									if(bHandleLine)
1436cdf0e10cSrcweir 									{
1437cdf0e10cSrcweir 										pLineTarget->append(aSnippet);
1438cdf0e10cSrcweir 									}
1439cdf0e10cSrcweir 									else
1440cdf0e10cSrcweir 									{
1441cdf0e10cSrcweir 										pGapTarget->append(aSnippet);
1442cdf0e10cSrcweir 									}
1443cdf0e10cSrcweir 
1444cdf0e10cSrcweir 									aSnippet.clear();
1445cdf0e10cSrcweir 								}
1446cdf0e10cSrcweir 
1447cdf0e10cSrcweir 								// prepare next DotDashArray step and flip line/gap flag
1448cdf0e10cSrcweir 								fLastDotDashMovingLength = fDotDashMovingLength;
1449cdf0e10cSrcweir 								fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
1450cdf0e10cSrcweir 								bIsLine = !bIsLine;
1451cdf0e10cSrcweir 							}
1452cdf0e10cSrcweir 
1453cdf0e10cSrcweir 							// append snippet [fLastDotDashMovingLength, fEdgeLength]
1454cdf0e10cSrcweir 							const bool bHandleLine(bIsLine && pLineTarget);
1455cdf0e10cSrcweir 							const bool bHandleGap(!bIsLine && pGapTarget);
1456cdf0e10cSrcweir 
1457cdf0e10cSrcweir 							if(bHandleLine || bHandleGap)
1458cdf0e10cSrcweir 							{
1459cdf0e10cSrcweir 								if(!aSnippet.count())
1460cdf0e10cSrcweir 								{
1461cdf0e10cSrcweir 									aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fLastDotDashMovingLength / fEdgeLength));
1462cdf0e10cSrcweir 								}
1463cdf0e10cSrcweir 
1464cdf0e10cSrcweir 								aSnippet.append(aCurrentEdge.getEndPoint());
1465cdf0e10cSrcweir 							}
1466cdf0e10cSrcweir 
1467cdf0e10cSrcweir 							// prepare move to next edge
1468cdf0e10cSrcweir 							fDotDashMovingLength -= fEdgeLength;
1469cdf0e10cSrcweir 						}
1470cdf0e10cSrcweir 					}
1471cdf0e10cSrcweir 
1472cdf0e10cSrcweir 					// prepare next edge step (end point gets new start point)
1473cdf0e10cSrcweir                     aCurrentEdge.setStartPoint(aCurrentEdge.getEndPoint());
1474cdf0e10cSrcweir                 }
1475cdf0e10cSrcweir 
1476cdf0e10cSrcweir                 // append last intermediate results (if exists)
1477cdf0e10cSrcweir                 if(aSnippet.count())
1478cdf0e10cSrcweir                 {
1479cdf0e10cSrcweir                     if(bIsLine && pLineTarget)
1480cdf0e10cSrcweir                     {
1481cdf0e10cSrcweir                         pLineTarget->append(aSnippet);
1482cdf0e10cSrcweir                     }
1483cdf0e10cSrcweir                     else if(!bIsLine && pGapTarget)
1484cdf0e10cSrcweir                     {
1485cdf0e10cSrcweir                         pGapTarget->append(aSnippet);
1486cdf0e10cSrcweir                     }
1487cdf0e10cSrcweir                 }
1488cdf0e10cSrcweir 
1489cdf0e10cSrcweir 				// check if start and end polygon may be merged
1490cdf0e10cSrcweir 				if(pLineTarget)
1491cdf0e10cSrcweir 				{
1492cdf0e10cSrcweir 					const sal_uInt32 nCount(pLineTarget->count());
1493cdf0e10cSrcweir 
1494cdf0e10cSrcweir 					if(nCount > 1)
1495cdf0e10cSrcweir 					{
1496cdf0e10cSrcweir 						// these polygons were created above, there exists none with less than two points,
1497cdf0e10cSrcweir 						// thus dircet point access below is allowed
1498cdf0e10cSrcweir 						const B2DPolygon aFirst(pLineTarget->getB2DPolygon(0));
1499cdf0e10cSrcweir 						B2DPolygon aLast(pLineTarget->getB2DPolygon(nCount - 1));
1500cdf0e10cSrcweir 
1501cdf0e10cSrcweir 						if(aFirst.getB2DPoint(0).equal(aLast.getB2DPoint(aLast.count() - 1)))
1502cdf0e10cSrcweir 						{
1503cdf0e10cSrcweir 							// start of first and end of last are the same -> merge them
1504cdf0e10cSrcweir 							aLast.append(aFirst);
1505cdf0e10cSrcweir 							aLast.removeDoublePoints();
1506cdf0e10cSrcweir 							pLineTarget->setB2DPolygon(0, aLast);
1507cdf0e10cSrcweir 							pLineTarget->remove(nCount - 1);
1508cdf0e10cSrcweir 						}
1509cdf0e10cSrcweir 					}
1510cdf0e10cSrcweir 				}
1511cdf0e10cSrcweir 
1512cdf0e10cSrcweir 				if(pGapTarget)
1513cdf0e10cSrcweir 				{
1514cdf0e10cSrcweir 					const sal_uInt32 nCount(pGapTarget->count());
1515cdf0e10cSrcweir 
1516cdf0e10cSrcweir 					if(nCount > 1)
1517cdf0e10cSrcweir 					{
1518cdf0e10cSrcweir 						// these polygons were created above, there exists none with less than two points,
1519cdf0e10cSrcweir 						// thus dircet point access below is allowed
1520cdf0e10cSrcweir 						const B2DPolygon aFirst(pGapTarget->getB2DPolygon(0));
1521cdf0e10cSrcweir 						B2DPolygon aLast(pGapTarget->getB2DPolygon(nCount - 1));
1522cdf0e10cSrcweir 
1523cdf0e10cSrcweir 						if(aFirst.getB2DPoint(0).equal(aLast.getB2DPoint(aLast.count() - 1)))
1524cdf0e10cSrcweir 						{
1525cdf0e10cSrcweir 							// start of first and end of last are the same -> merge them
1526cdf0e10cSrcweir 							aLast.append(aFirst);
1527cdf0e10cSrcweir 							aLast.removeDoublePoints();
1528cdf0e10cSrcweir 							pGapTarget->setB2DPolygon(0, aLast);
1529cdf0e10cSrcweir 							pGapTarget->remove(nCount - 1);
1530cdf0e10cSrcweir 						}
1531cdf0e10cSrcweir 					}
1532cdf0e10cSrcweir 				}
1533cdf0e10cSrcweir             }
1534cdf0e10cSrcweir             else
1535cdf0e10cSrcweir             {
1536cdf0e10cSrcweir 				// parameters make no sense, just add source to targets
1537cdf0e10cSrcweir                 if(pLineTarget)
1538cdf0e10cSrcweir                 {
1539cdf0e10cSrcweir                     pLineTarget->append(rCandidate);
1540cdf0e10cSrcweir                 }
1541cdf0e10cSrcweir 
1542cdf0e10cSrcweir 				if(pGapTarget)
1543cdf0e10cSrcweir 				{
1544cdf0e10cSrcweir                     pGapTarget->append(rCandidate);
1545cdf0e10cSrcweir 				}
1546cdf0e10cSrcweir             }
1547cdf0e10cSrcweir 		}
1548cdf0e10cSrcweir 
1549cdf0e10cSrcweir 		// test if point is inside epsilon-range around an edge defined
1550cdf0e10cSrcweir 		// by the two given points. Can be used for HitTesting. The epsilon-range
1551cdf0e10cSrcweir 		// is defined to be the rectangle centered to the given edge, using height
1552cdf0e10cSrcweir 		// 2 x fDistance, and the circle around both points with radius fDistance.
isInEpsilonRange(const B2DPoint & rEdgeStart,const B2DPoint & rEdgeEnd,const B2DPoint & rTestPosition,double fDistance)1553cdf0e10cSrcweir 		bool isInEpsilonRange(const B2DPoint& rEdgeStart, const B2DPoint& rEdgeEnd, const B2DPoint& rTestPosition, double fDistance)
1554cdf0e10cSrcweir 		{
1555cdf0e10cSrcweir 			// build edge vector
1556cdf0e10cSrcweir 			const B2DVector aEdge(rEdgeEnd - rEdgeStart);
1557cdf0e10cSrcweir 			bool bDoDistanceTestStart(false);
1558cdf0e10cSrcweir 			bool bDoDistanceTestEnd(false);
1559cdf0e10cSrcweir 
1560cdf0e10cSrcweir 			if(aEdge.equalZero())
1561cdf0e10cSrcweir 			{
1562cdf0e10cSrcweir 				// no edge, just a point. Do one of the distance tests.
1563cdf0e10cSrcweir 				bDoDistanceTestStart = true;
1564cdf0e10cSrcweir 			}
1565cdf0e10cSrcweir 			else
1566cdf0e10cSrcweir 			{
1567cdf0e10cSrcweir 				// edge has a length. Create perpendicular vector.
1568cdf0e10cSrcweir 				const B2DVector aPerpend(getPerpendicular(aEdge));
1569cdf0e10cSrcweir 				double fCut(
1570cdf0e10cSrcweir 					(aPerpend.getY() * (rTestPosition.getX() - rEdgeStart.getX())
1571cdf0e10cSrcweir 					+ aPerpend.getX() * (rEdgeStart.getY() - rTestPosition.getY())) /
1572cdf0e10cSrcweir 					(aEdge.getX() * aEdge.getX() + aEdge.getY() * aEdge.getY()));
1573cdf0e10cSrcweir 				const double fZero(0.0);
1574cdf0e10cSrcweir 				const double fOne(1.0);
1575cdf0e10cSrcweir 
1576cdf0e10cSrcweir 				if(fTools::less(fCut, fZero))
1577cdf0e10cSrcweir 				{
1578cdf0e10cSrcweir 					// left of rEdgeStart
1579cdf0e10cSrcweir 					bDoDistanceTestStart = true;
1580cdf0e10cSrcweir 				}
1581cdf0e10cSrcweir 				else if(fTools::more(fCut, fOne))
1582cdf0e10cSrcweir 				{
1583cdf0e10cSrcweir 					// right of rEdgeEnd
1584cdf0e10cSrcweir 					bDoDistanceTestEnd = true;
1585cdf0e10cSrcweir 				}
1586cdf0e10cSrcweir 				else
1587cdf0e10cSrcweir 				{
1588cdf0e10cSrcweir 					// inside line [0.0 .. 1.0]
1589cdf0e10cSrcweir 					const B2DPoint aCutPoint(interpolate(rEdgeStart, rEdgeEnd, fCut));
1590cdf0e10cSrcweir     			    const B2DVector aDelta(rTestPosition - aCutPoint);
1591cdf0e10cSrcweir 					const double fDistanceSquare(aDelta.scalar(aDelta));
1592cdf0e10cSrcweir 
1593cdf0e10cSrcweir 					if(fDistanceSquare <= fDistance * fDistance)
1594cdf0e10cSrcweir 					{
1595cdf0e10cSrcweir 						return true;
1596cdf0e10cSrcweir 					}
1597cdf0e10cSrcweir 					else
1598cdf0e10cSrcweir 					{
1599cdf0e10cSrcweir 						return false;
1600cdf0e10cSrcweir 					}
1601cdf0e10cSrcweir 				}
1602cdf0e10cSrcweir 			}
1603cdf0e10cSrcweir 
1604cdf0e10cSrcweir 			if(bDoDistanceTestStart)
1605cdf0e10cSrcweir 			{
1606cdf0e10cSrcweir 			    const B2DVector aDelta(rTestPosition - rEdgeStart);
1607cdf0e10cSrcweir 				const double fDistanceSquare(aDelta.scalar(aDelta));
1608cdf0e10cSrcweir 
1609cdf0e10cSrcweir 				if(fDistanceSquare <= fDistance * fDistance)
1610cdf0e10cSrcweir 				{
1611cdf0e10cSrcweir 					return true;
1612cdf0e10cSrcweir 				}
1613cdf0e10cSrcweir 			}
1614cdf0e10cSrcweir 			else if(bDoDistanceTestEnd)
1615cdf0e10cSrcweir 			{
1616cdf0e10cSrcweir 			    const B2DVector aDelta(rTestPosition - rEdgeEnd);
1617cdf0e10cSrcweir 				const double fDistanceSquare(aDelta.scalar(aDelta));
1618cdf0e10cSrcweir 
1619cdf0e10cSrcweir 				if(fDistanceSquare <= fDistance * fDistance)
1620cdf0e10cSrcweir 				{
1621cdf0e10cSrcweir 					return true;
1622cdf0e10cSrcweir 				}
1623cdf0e10cSrcweir 			}
1624cdf0e10cSrcweir 
1625cdf0e10cSrcweir 			return false;
1626cdf0e10cSrcweir 		}
1627cdf0e10cSrcweir 
1628cdf0e10cSrcweir 		// test if point is inside epsilon-range around the given Polygon. Can be used
1629cdf0e10cSrcweir 		// for HitTesting. The epsilon-range is defined to be the tube around the polygon
1630cdf0e10cSrcweir 		// with distance fDistance and rounded edges (start and end point).
isInEpsilonRange(const B2DPolygon & rCandidate,const B2DPoint & rTestPosition,double fDistance)1631cdf0e10cSrcweir 		bool isInEpsilonRange(const B2DPolygon& rCandidate, const B2DPoint& rTestPosition, double fDistance)
1632cdf0e10cSrcweir 		{
1633cdf0e10cSrcweir 			// force to non-bezier polygon
1634cdf0e10cSrcweir 			const B2DPolygon aCandidate(rCandidate.getDefaultAdaptiveSubdivision());
1635cdf0e10cSrcweir 			const sal_uInt32 nPointCount(aCandidate.count());
1636cdf0e10cSrcweir 
1637cdf0e10cSrcweir 			if(nPointCount)
1638cdf0e10cSrcweir 			{
1639cdf0e10cSrcweir                 const sal_uInt32 nEdgeCount(aCandidate.isClosed() ? nPointCount : nPointCount - 1L);
1640cdf0e10cSrcweir 				B2DPoint aCurrent(aCandidate.getB2DPoint(0));
1641cdf0e10cSrcweir 
1642cdf0e10cSrcweir 				if(nEdgeCount)
1643cdf0e10cSrcweir 				{
1644cdf0e10cSrcweir 					// edges
1645cdf0e10cSrcweir 					for(sal_uInt32 a(0); a < nEdgeCount; a++)
1646cdf0e10cSrcweir 					{
1647cdf0e10cSrcweir 						const sal_uInt32 nNextIndex((a + 1) % nPointCount);
1648cdf0e10cSrcweir 						const B2DPoint aNext(aCandidate.getB2DPoint(nNextIndex));
1649cdf0e10cSrcweir 
1650cdf0e10cSrcweir 						if(isInEpsilonRange(aCurrent, aNext, rTestPosition, fDistance))
1651cdf0e10cSrcweir 						{
1652cdf0e10cSrcweir 							return true;
1653cdf0e10cSrcweir 						}
1654cdf0e10cSrcweir 
1655cdf0e10cSrcweir 						// prepare next step
1656cdf0e10cSrcweir 						aCurrent = aNext;
1657cdf0e10cSrcweir 					}
1658cdf0e10cSrcweir 				}
1659cdf0e10cSrcweir 				else
1660cdf0e10cSrcweir 				{
1661cdf0e10cSrcweir 					// no edges, but points -> not closed. Check single point. Just
1662cdf0e10cSrcweir 					// use isInEpsilonRange with twice the same point, it handles those well
1663cdf0e10cSrcweir 					if(isInEpsilonRange(aCurrent, aCurrent, rTestPosition, fDistance))
1664cdf0e10cSrcweir 					{
1665cdf0e10cSrcweir 						return true;
1666cdf0e10cSrcweir 					}
1667cdf0e10cSrcweir 				}
1668cdf0e10cSrcweir 			}
1669cdf0e10cSrcweir 
1670cdf0e10cSrcweir 			return false;
1671cdf0e10cSrcweir 		}
1672cdf0e10cSrcweir 
createPolygonFromRect(const B2DRectangle & rRect,double fRadius)1673cdf0e10cSrcweir         B2DPolygon createPolygonFromRect( const B2DRectangle& rRect, double fRadius )
1674cdf0e10cSrcweir         {
1675cdf0e10cSrcweir 			const double fZero(0.0);
1676cdf0e10cSrcweir 			const double fOne(1.0);
1677cdf0e10cSrcweir 
1678cdf0e10cSrcweir 			if(fTools::lessOrEqual(fRadius, fZero))
1679cdf0e10cSrcweir 			{
1680cdf0e10cSrcweir 				// no radius, use rectangle
1681cdf0e10cSrcweir 				return createPolygonFromRect( rRect );
1682cdf0e10cSrcweir 			}
1683cdf0e10cSrcweir 			else if(fTools::moreOrEqual(fRadius, fOne))
1684cdf0e10cSrcweir 			{
1685cdf0e10cSrcweir 				// full radius, use ellipse
1686cdf0e10cSrcweir 				const B2DPoint aCenter(rRect.getCenter());
1687cdf0e10cSrcweir 				const double fRadiusX(rRect.getWidth() / 2.0);
1688cdf0e10cSrcweir 				const double fRadiusY(rRect.getHeight() / 2.0);
1689cdf0e10cSrcweir 
1690cdf0e10cSrcweir 				return createPolygonFromEllipse( aCenter, fRadiusX, fRadiusY );
1691cdf0e10cSrcweir 			}
1692cdf0e10cSrcweir 			else
1693cdf0e10cSrcweir 			{
1694cdf0e10cSrcweir 				// create rectangle with two radii between ]0.0 .. 1.0[
1695cdf0e10cSrcweir 				return createPolygonFromRect( rRect, fRadius, fRadius );
1696cdf0e10cSrcweir 			}
1697cdf0e10cSrcweir 		}
1698cdf0e10cSrcweir 
createPolygonFromRect(const B2DRectangle & rRect,double fRadiusX,double fRadiusY)1699cdf0e10cSrcweir         B2DPolygon createPolygonFromRect( const B2DRectangle& rRect, double fRadiusX, double fRadiusY )
1700cdf0e10cSrcweir         {
1701cdf0e10cSrcweir 			const double fZero(0.0);
1702cdf0e10cSrcweir 			const double fOne(1.0);
1703cdf0e10cSrcweir 
1704cdf0e10cSrcweir 			// crop to useful values
1705cdf0e10cSrcweir 			if(fTools::less(fRadiusX, fZero))
1706cdf0e10cSrcweir 			{
1707cdf0e10cSrcweir 				fRadiusX = fZero;
1708cdf0e10cSrcweir 			}
1709cdf0e10cSrcweir 			else if(fTools::more(fRadiusX, fOne))
1710cdf0e10cSrcweir 			{
1711cdf0e10cSrcweir 				fRadiusX = fOne;
1712cdf0e10cSrcweir 			}
1713cdf0e10cSrcweir 
1714cdf0e10cSrcweir 			if(fTools::less(fRadiusY, fZero))
1715cdf0e10cSrcweir 			{
1716cdf0e10cSrcweir 				fRadiusY = fZero;
1717cdf0e10cSrcweir 			}
1718cdf0e10cSrcweir 			else if(fTools::more(fRadiusY, fOne))
1719cdf0e10cSrcweir 			{
1720cdf0e10cSrcweir 				fRadiusY = fOne;
1721cdf0e10cSrcweir 			}
1722cdf0e10cSrcweir 
1723cdf0e10cSrcweir 			if(fZero == fRadiusX || fZero == fRadiusY)
1724cdf0e10cSrcweir 			{
1725cdf0e10cSrcweir 				B2DPolygon aRetval;
1726cdf0e10cSrcweir 
1727cdf0e10cSrcweir 				// at least in one direction no radius, use rectangle.
1728cdf0e10cSrcweir 				// Do not use createPolygonFromRect() here since original
1729cdf0e10cSrcweir 				// creator (historical reasons) still creates a start point at the
1730cdf0e10cSrcweir 				// bottom center, so do the same here to get the same line patterns.
1731cdf0e10cSrcweir 				// Due to this the order of points is different, too.
1732cdf0e10cSrcweir 				const B2DPoint aBottomCenter(rRect.getCenter().getX(), rRect.getMaxY());
1733cdf0e10cSrcweir 				aRetval.append(aBottomCenter);
1734cdf0e10cSrcweir 
1735cdf0e10cSrcweir 				aRetval.append( B2DPoint( rRect.getMinX(), rRect.getMaxY() ) );
1736cdf0e10cSrcweir 				aRetval.append( B2DPoint( rRect.getMinX(), rRect.getMinY() ) );
1737cdf0e10cSrcweir 				aRetval.append( B2DPoint( rRect.getMaxX(), rRect.getMinY() ) );
1738cdf0e10cSrcweir 				aRetval.append( B2DPoint( rRect.getMaxX(), rRect.getMaxY() ) );
1739cdf0e10cSrcweir 
1740cdf0e10cSrcweir 				// close
1741cdf0e10cSrcweir 				aRetval.setClosed( true );
1742cdf0e10cSrcweir 
1743cdf0e10cSrcweir 				return aRetval;
1744cdf0e10cSrcweir 			}
1745cdf0e10cSrcweir 			else if(fOne == fRadiusX && fOne == fRadiusY)
1746cdf0e10cSrcweir 			{
1747cdf0e10cSrcweir 				// in both directions full radius, use ellipse
1748cdf0e10cSrcweir 				const B2DPoint aCenter(rRect.getCenter());
1749cdf0e10cSrcweir 				const double fRectRadiusX(rRect.getWidth() / 2.0);
1750cdf0e10cSrcweir 				const double fRectRadiusY(rRect.getHeight() / 2.0);
1751cdf0e10cSrcweir 
1752cdf0e10cSrcweir 				return createPolygonFromEllipse( aCenter, fRectRadiusX, fRectRadiusY );
1753cdf0e10cSrcweir 			}
1754cdf0e10cSrcweir 			else
1755cdf0e10cSrcweir 			{
1756cdf0e10cSrcweir 				B2DPolygon aRetval;
1757cdf0e10cSrcweir 				const double fBowX((rRect.getWidth() / 2.0) * fRadiusX);
1758cdf0e10cSrcweir 				const double fBowY((rRect.getHeight() / 2.0) * fRadiusY);
1759cdf0e10cSrcweir 	            const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
1760cdf0e10cSrcweir 
1761cdf0e10cSrcweir 				// create start point at bottom center
1762cdf0e10cSrcweir 				if(fOne != fRadiusX)
1763cdf0e10cSrcweir 				{
1764cdf0e10cSrcweir 					const B2DPoint aBottomCenter(rRect.getCenter().getX(), rRect.getMaxY());
1765cdf0e10cSrcweir 					aRetval.append(aBottomCenter);
1766cdf0e10cSrcweir 				}
1767cdf0e10cSrcweir 
1768cdf0e10cSrcweir 				// create first bow
1769cdf0e10cSrcweir 				{
1770cdf0e10cSrcweir 					const B2DPoint aBottomRight(rRect.getMaxX(), rRect.getMaxY());
1771cdf0e10cSrcweir 					const B2DPoint aStart(aBottomRight + B2DPoint(-fBowX, 0.0));
1772cdf0e10cSrcweir 					const B2DPoint aStop(aBottomRight + B2DPoint(0.0, -fBowY));
1773cdf0e10cSrcweir 					aRetval.append(aStart);
1774cdf0e10cSrcweir 					aRetval.appendBezierSegment(interpolate(aStart, aBottomRight, fKappa), interpolate(aStop, aBottomRight, fKappa), aStop);
1775cdf0e10cSrcweir 				}
1776cdf0e10cSrcweir 
1777cdf0e10cSrcweir 				// create second bow
1778cdf0e10cSrcweir 				{
1779cdf0e10cSrcweir 					const B2DPoint aTopRight(rRect.getMaxX(), rRect.getMinY());
1780cdf0e10cSrcweir 					const B2DPoint aStart(aTopRight + B2DPoint(0.0, fBowY));
1781cdf0e10cSrcweir 					const B2DPoint aStop(aTopRight + B2DPoint(-fBowX, 0.0));
1782cdf0e10cSrcweir 					aRetval.append(aStart);
1783cdf0e10cSrcweir 					aRetval.appendBezierSegment(interpolate(aStart, aTopRight, fKappa), interpolate(aStop, aTopRight, fKappa), aStop);
1784cdf0e10cSrcweir 				}
1785cdf0e10cSrcweir 
1786cdf0e10cSrcweir 				// create third bow
1787cdf0e10cSrcweir 				{
1788cdf0e10cSrcweir 					const B2DPoint aTopLeft(rRect.getMinX(), rRect.getMinY());
1789cdf0e10cSrcweir 					const B2DPoint aStart(aTopLeft + B2DPoint(fBowX, 0.0));
1790cdf0e10cSrcweir 					const B2DPoint aStop(aTopLeft + B2DPoint(0.0, fBowY));
1791cdf0e10cSrcweir 					aRetval.append(aStart);
1792cdf0e10cSrcweir 					aRetval.appendBezierSegment(interpolate(aStart, aTopLeft, fKappa), interpolate(aStop, aTopLeft, fKappa), aStop);
1793cdf0e10cSrcweir 				}
1794cdf0e10cSrcweir 
1795cdf0e10cSrcweir 				// create forth bow
1796cdf0e10cSrcweir 				{
1797cdf0e10cSrcweir 					const B2DPoint aBottomLeft(rRect.getMinX(), rRect.getMaxY());
1798cdf0e10cSrcweir 					const B2DPoint aStart(aBottomLeft + B2DPoint(0.0, -fBowY));
1799cdf0e10cSrcweir 					const B2DPoint aStop(aBottomLeft + B2DPoint(fBowX, 0.0));
1800cdf0e10cSrcweir 					aRetval.append(aStart);
1801cdf0e10cSrcweir 					aRetval.appendBezierSegment(interpolate(aStart, aBottomLeft, fKappa), interpolate(aStop, aBottomLeft, fKappa), aStop);
1802cdf0e10cSrcweir 				}
1803cdf0e10cSrcweir 
1804cdf0e10cSrcweir 				// close
1805cdf0e10cSrcweir 	            aRetval.setClosed( true );
1806cdf0e10cSrcweir 
1807cdf0e10cSrcweir 				// remove double created points if there are extreme radii envolved
1808cdf0e10cSrcweir 				if(fOne == fRadiusX || fOne == fRadiusY)
1809cdf0e10cSrcweir 				{
1810cdf0e10cSrcweir 					aRetval.removeDoublePoints();
1811cdf0e10cSrcweir 				}
1812cdf0e10cSrcweir 
1813cdf0e10cSrcweir 				return aRetval;
1814cdf0e10cSrcweir 			}
1815cdf0e10cSrcweir 		}
1816cdf0e10cSrcweir 
createPolygonFromRect(const B2DRectangle & rRect)1817cdf0e10cSrcweir         B2DPolygon createPolygonFromRect( const B2DRectangle& rRect )
1818cdf0e10cSrcweir         {
1819cdf0e10cSrcweir             B2DPolygon aRetval;
1820cdf0e10cSrcweir 
1821cdf0e10cSrcweir             aRetval.append( B2DPoint( rRect.getMinX(), rRect.getMinY() ) );
1822cdf0e10cSrcweir             aRetval.append( B2DPoint( rRect.getMaxX(), rRect.getMinY() ) );
1823cdf0e10cSrcweir             aRetval.append( B2DPoint( rRect.getMaxX(), rRect.getMaxY() ) );
1824cdf0e10cSrcweir             aRetval.append( B2DPoint( rRect.getMinX(), rRect.getMaxY() ) );
1825cdf0e10cSrcweir 
1826cdf0e10cSrcweir 			// close
1827cdf0e10cSrcweir 			aRetval.setClosed( true );
1828cdf0e10cSrcweir 
1829cdf0e10cSrcweir             return aRetval;
1830cdf0e10cSrcweir         }
1831cdf0e10cSrcweir 
createUnitPolygon()1832cdf0e10cSrcweir         B2DPolygon createUnitPolygon()
1833cdf0e10cSrcweir         {
1834cdf0e10cSrcweir             static B2DPolygon aRetval;
1835cdf0e10cSrcweir 
1836cdf0e10cSrcweir             if(!aRetval.count())
1837cdf0e10cSrcweir             {
1838cdf0e10cSrcweir                 aRetval.append( B2DPoint( 0.0, 0.0 ) );
1839cdf0e10cSrcweir                 aRetval.append( B2DPoint( 1.0, 0.0 ) );
1840cdf0e10cSrcweir                 aRetval.append( B2DPoint( 1.0, 1.0 ) );
1841cdf0e10cSrcweir                 aRetval.append( B2DPoint( 0.0, 1.0 ) );
1842cdf0e10cSrcweir 
1843cdf0e10cSrcweir 			    // close
1844cdf0e10cSrcweir 			    aRetval.setClosed( true );
1845cdf0e10cSrcweir             }
1846cdf0e10cSrcweir 
1847cdf0e10cSrcweir             return aRetval;
1848cdf0e10cSrcweir         }
1849cdf0e10cSrcweir 
createPolygonFromCircle(const B2DPoint & rCenter,double fRadius)1850cdf0e10cSrcweir         B2DPolygon createPolygonFromCircle( const B2DPoint& rCenter, double fRadius )
1851cdf0e10cSrcweir         {
1852cdf0e10cSrcweir             return createPolygonFromEllipse( rCenter, fRadius, fRadius );
1853cdf0e10cSrcweir         }
1854cdf0e10cSrcweir 
impCreateUnitCircle(sal_uInt32 nStartQuadrant)1855cdf0e10cSrcweir         B2DPolygon impCreateUnitCircle(sal_uInt32 nStartQuadrant)
1856cdf0e10cSrcweir         {
1857cdf0e10cSrcweir             B2DPolygon aUnitCircle;
1858cdf0e10cSrcweir 	        const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
1859cdf0e10cSrcweir             const double fScaledKappa(fKappa * (1.0 / STEPSPERQUARTER));
1860cdf0e10cSrcweir             const B2DHomMatrix aRotateMatrix(createRotateB2DHomMatrix(F_PI2 / STEPSPERQUARTER));
1861cdf0e10cSrcweir 
1862cdf0e10cSrcweir             B2DPoint aPoint(1.0, 0.0);
1863cdf0e10cSrcweir             B2DPoint aForward(1.0, fScaledKappa);
1864cdf0e10cSrcweir             B2DPoint aBackward(1.0, -fScaledKappa);
1865cdf0e10cSrcweir 
1866cdf0e10cSrcweir             if(0 != nStartQuadrant)
1867cdf0e10cSrcweir             {
1868cdf0e10cSrcweir                 const B2DHomMatrix aQuadrantMatrix(createRotateB2DHomMatrix(F_PI2 * (nStartQuadrant % 4)));
1869cdf0e10cSrcweir                 aPoint *= aQuadrantMatrix;
1870cdf0e10cSrcweir                 aBackward *= aQuadrantMatrix;
1871cdf0e10cSrcweir                 aForward *= aQuadrantMatrix;
1872cdf0e10cSrcweir             }
1873cdf0e10cSrcweir 
1874cdf0e10cSrcweir             aUnitCircle.append(aPoint);
1875cdf0e10cSrcweir 
1876cdf0e10cSrcweir             for(sal_uInt32 a(0); a < STEPSPERQUARTER * 4; a++)
1877cdf0e10cSrcweir             {
1878cdf0e10cSrcweir                 aPoint *= aRotateMatrix;
1879cdf0e10cSrcweir                 aBackward *= aRotateMatrix;
1880cdf0e10cSrcweir                 aUnitCircle.appendBezierSegment(aForward, aBackward, aPoint);
1881cdf0e10cSrcweir                 aForward *= aRotateMatrix;
1882cdf0e10cSrcweir             }
1883cdf0e10cSrcweir 
1884cdf0e10cSrcweir             aUnitCircle.setClosed(true);
1885cdf0e10cSrcweir 		    aUnitCircle.removeDoublePoints();
1886cdf0e10cSrcweir 
1887cdf0e10cSrcweir             return aUnitCircle;
1888cdf0e10cSrcweir         }
18895aaf853bSArmin Le Grand 
createHalfUnitCircle()18905aaf853bSArmin Le Grand         B2DPolygon createHalfUnitCircle()
18915aaf853bSArmin Le Grand         {
18925aaf853bSArmin Le Grand             static B2DPolygon aUnitHalfCircle;
18935aaf853bSArmin Le Grand 
18945aaf853bSArmin Le Grand             if(!aUnitHalfCircle.count())
18955aaf853bSArmin Le Grand             {
18965aaf853bSArmin Le Grand                 const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
18975aaf853bSArmin Le Grand                 const double fScaledKappa(fKappa * (1.0 / STEPSPERQUARTER));
18985aaf853bSArmin Le Grand                 const B2DHomMatrix aRotateMatrix(createRotateB2DHomMatrix(F_PI2 / STEPSPERQUARTER));
18995aaf853bSArmin Le Grand                 B2DPoint aPoint(1.0, 0.0);
19005aaf853bSArmin Le Grand                 B2DPoint aForward(1.0, fScaledKappa);
19015aaf853bSArmin Le Grand                 B2DPoint aBackward(1.0, -fScaledKappa);
19025aaf853bSArmin Le Grand 
19035aaf853bSArmin Le Grand                 aUnitHalfCircle.append(aPoint);
19045aaf853bSArmin Le Grand 
19055aaf853bSArmin Le Grand                 for(sal_uInt32 a(0); a < STEPSPERQUARTER * 2; a++)
19065aaf853bSArmin Le Grand                 {
19075aaf853bSArmin Le Grand                     aPoint *= aRotateMatrix;
19085aaf853bSArmin Le Grand                     aBackward *= aRotateMatrix;
19095aaf853bSArmin Le Grand                     aUnitHalfCircle.appendBezierSegment(aForward, aBackward, aPoint);
19105aaf853bSArmin Le Grand                     aForward *= aRotateMatrix;
19115aaf853bSArmin Le Grand                 }
19125aaf853bSArmin Le Grand             }
19135aaf853bSArmin Le Grand 
19145aaf853bSArmin Le Grand             return aUnitHalfCircle;
19155aaf853bSArmin Le Grand         }
1916cdf0e10cSrcweir 
createPolygonFromUnitCircle(sal_uInt32 nStartQuadrant)1917cdf0e10cSrcweir         B2DPolygon createPolygonFromUnitCircle(sal_uInt32 nStartQuadrant)
1918cdf0e10cSrcweir 		{
1919cdf0e10cSrcweir             switch(nStartQuadrant % 4)
1920cdf0e10cSrcweir             {
1921cdf0e10cSrcweir                 case 1 :
1922cdf0e10cSrcweir                 {
1923cdf0e10cSrcweir         			static B2DPolygon aUnitCircleStartQuadrantOne;
1924cdf0e10cSrcweir 
1925cdf0e10cSrcweir                     if(!aUnitCircleStartQuadrantOne.count())
1926cdf0e10cSrcweir                     {
1927cdf0e10cSrcweir     		            ::osl::Mutex m_mutex;
1928cdf0e10cSrcweir                         aUnitCircleStartQuadrantOne = impCreateUnitCircle(1);
1929cdf0e10cSrcweir                     }
1930cdf0e10cSrcweir 
1931cdf0e10cSrcweir                     return aUnitCircleStartQuadrantOne;
1932cdf0e10cSrcweir                 }
1933cdf0e10cSrcweir                 case 2 :
1934cdf0e10cSrcweir                 {
1935cdf0e10cSrcweir         			static B2DPolygon aUnitCircleStartQuadrantTwo;
1936cdf0e10cSrcweir 
1937cdf0e10cSrcweir                     if(!aUnitCircleStartQuadrantTwo.count())
1938cdf0e10cSrcweir                     {
1939cdf0e10cSrcweir     		            ::osl::Mutex m_mutex;
1940cdf0e10cSrcweir                         aUnitCircleStartQuadrantTwo = impCreateUnitCircle(2);
1941cdf0e10cSrcweir                     }
1942cdf0e10cSrcweir 
1943cdf0e10cSrcweir                     return aUnitCircleStartQuadrantTwo;
1944cdf0e10cSrcweir                 }
1945cdf0e10cSrcweir                 case 3 :
1946cdf0e10cSrcweir                 {
1947cdf0e10cSrcweir         			static B2DPolygon aUnitCircleStartQuadrantThree;
1948cdf0e10cSrcweir 
1949cdf0e10cSrcweir                     if(!aUnitCircleStartQuadrantThree.count())
1950cdf0e10cSrcweir                     {
1951cdf0e10cSrcweir     		            ::osl::Mutex m_mutex;
1952cdf0e10cSrcweir                         aUnitCircleStartQuadrantThree = impCreateUnitCircle(3);
1953cdf0e10cSrcweir                     }
1954cdf0e10cSrcweir 
1955cdf0e10cSrcweir                     return aUnitCircleStartQuadrantThree;
1956cdf0e10cSrcweir                 }
1957cdf0e10cSrcweir                 default : // case 0 :
1958cdf0e10cSrcweir                 {
1959cdf0e10cSrcweir         			static B2DPolygon aUnitCircleStartQuadrantZero;
1960cdf0e10cSrcweir 
1961cdf0e10cSrcweir                     if(!aUnitCircleStartQuadrantZero.count())
1962cdf0e10cSrcweir                     {
1963cdf0e10cSrcweir     		            ::osl::Mutex m_mutex;
1964cdf0e10cSrcweir                         aUnitCircleStartQuadrantZero = impCreateUnitCircle(0);
1965cdf0e10cSrcweir                     }
1966cdf0e10cSrcweir 
1967cdf0e10cSrcweir                     return aUnitCircleStartQuadrantZero;
1968cdf0e10cSrcweir                 }
1969cdf0e10cSrcweir             }
1970cdf0e10cSrcweir 		}
1971cdf0e10cSrcweir 
createPolygonFromEllipse(const B2DPoint & rCenter,double fRadiusX,double fRadiusY)1972cdf0e10cSrcweir         B2DPolygon createPolygonFromEllipse( const B2DPoint& rCenter, double fRadiusX, double fRadiusY )
1973cdf0e10cSrcweir         {
1974cdf0e10cSrcweir 			B2DPolygon aRetval(createPolygonFromUnitCircle());
1975cdf0e10cSrcweir 			const B2DHomMatrix aMatrix(createScaleTranslateB2DHomMatrix(fRadiusX, fRadiusY, rCenter.getX(), rCenter.getY()));
1976cdf0e10cSrcweir 
1977cdf0e10cSrcweir 			aRetval.transform(aMatrix);
1978cdf0e10cSrcweir 
1979cdf0e10cSrcweir             return aRetval;
1980cdf0e10cSrcweir         }
1981cdf0e10cSrcweir 
createPolygonFromUnitEllipseSegment(double fStart,double fEnd)1982cdf0e10cSrcweir         B2DPolygon createPolygonFromUnitEllipseSegment( double fStart, double fEnd )
1983cdf0e10cSrcweir 		{
1984cdf0e10cSrcweir 	        B2DPolygon aRetval;
1985cdf0e10cSrcweir 
1986cdf0e10cSrcweir 			// truncate fStart, fEnd to a range of [0.0 .. F_2PI[ where F_2PI
1987cdf0e10cSrcweir 			// falls back to 0.0 to ensure a unique definition
1988cdf0e10cSrcweir 			if(fTools::less(fStart, 0.0))
1989cdf0e10cSrcweir 			{
1990cdf0e10cSrcweir 				fStart = 0.0;
1991cdf0e10cSrcweir 			}
1992cdf0e10cSrcweir 
1993cdf0e10cSrcweir 			if(fTools::moreOrEqual(fStart, F_2PI))
1994cdf0e10cSrcweir 			{
1995cdf0e10cSrcweir 				fStart = 0.0;
1996cdf0e10cSrcweir 			}
1997cdf0e10cSrcweir 
1998cdf0e10cSrcweir 			if(fTools::less(fEnd, 0.0))
1999cdf0e10cSrcweir 			{
2000cdf0e10cSrcweir 				fEnd = 0.0;
2001cdf0e10cSrcweir 			}
2002cdf0e10cSrcweir 
2003cdf0e10cSrcweir 			if(fTools::moreOrEqual(fEnd, F_2PI))
2004cdf0e10cSrcweir 			{
2005cdf0e10cSrcweir 				fEnd = 0.0;
2006cdf0e10cSrcweir 			}
2007cdf0e10cSrcweir 
2008cdf0e10cSrcweir 		    if(fTools::equal(fStart, fEnd))
2009cdf0e10cSrcweir             {
2010cdf0e10cSrcweir                 // same start and end angle, add single point
2011cdf0e10cSrcweir                 aRetval.append(B2DPoint(cos(fStart), sin(fStart)));
2012cdf0e10cSrcweir             }
2013cdf0e10cSrcweir             else
2014cdf0e10cSrcweir             {
2015cdf0e10cSrcweir                 const sal_uInt32 nSegments(STEPSPERQUARTER * 4);
2016cdf0e10cSrcweir                 const double fAnglePerSegment(F_PI2 / STEPSPERQUARTER);
2017cdf0e10cSrcweir                 const sal_uInt32 nStartSegment(sal_uInt32(fStart / fAnglePerSegment) % nSegments);
2018cdf0e10cSrcweir                 const sal_uInt32 nEndSegment(sal_uInt32(fEnd / fAnglePerSegment) % nSegments);
2019cdf0e10cSrcweir     	        const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
2020cdf0e10cSrcweir                 const double fScaledKappa(fKappa * (1.0 / STEPSPERQUARTER));
2021cdf0e10cSrcweir 
2022cdf0e10cSrcweir                 B2DPoint aSegStart(cos(fStart), sin(fStart));
2023cdf0e10cSrcweir                 aRetval.append(aSegStart);
2024cdf0e10cSrcweir 
2025cdf0e10cSrcweir                 if(nStartSegment == nEndSegment && fTools::more(fEnd, fStart))
2026cdf0e10cSrcweir                 {
2027cdf0e10cSrcweir                     // start and end in one sector and in the right order, create in one segment
2028cdf0e10cSrcweir                     const B2DPoint aSegEnd(cos(fEnd), sin(fEnd));
2029cdf0e10cSrcweir                     const double fFactor(fScaledKappa * ((fEnd - fStart) / fAnglePerSegment));
2030cdf0e10cSrcweir 
2031cdf0e10cSrcweir                     aRetval.appendBezierSegment(
2032cdf0e10cSrcweir                         aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fFactor),
2033cdf0e10cSrcweir                         aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fFactor),
2034cdf0e10cSrcweir                         aSegEnd);
2035cdf0e10cSrcweir                 }
2036cdf0e10cSrcweir                 else
2037cdf0e10cSrcweir                 {
2038cdf0e10cSrcweir                     double fSegEndRad((nStartSegment + 1) * fAnglePerSegment);
2039cdf0e10cSrcweir                     double fFactor(fScaledKappa * ((fSegEndRad - fStart) / fAnglePerSegment));
2040cdf0e10cSrcweir                     B2DPoint aSegEnd(cos(fSegEndRad), sin(fSegEndRad));
2041cdf0e10cSrcweir 
2042cdf0e10cSrcweir                     aRetval.appendBezierSegment(
2043cdf0e10cSrcweir                         aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fFactor),
2044cdf0e10cSrcweir                         aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fFactor),
2045cdf0e10cSrcweir                         aSegEnd);
2046cdf0e10cSrcweir 
2047cdf0e10cSrcweir                     sal_uInt32 nSegment((nStartSegment + 1) % nSegments);
2048cdf0e10cSrcweir                     aSegStart = aSegEnd;
2049cdf0e10cSrcweir 
2050cdf0e10cSrcweir                     while(nSegment != nEndSegment)
2051cdf0e10cSrcweir                     {
2052cdf0e10cSrcweir                         // No end in this sector, add full sector.
2053cdf0e10cSrcweir                         fSegEndRad = (nSegment + 1) * fAnglePerSegment;
2054cdf0e10cSrcweir                         aSegEnd = B2DPoint(cos(fSegEndRad), sin(fSegEndRad));
2055cdf0e10cSrcweir 
2056cdf0e10cSrcweir 				        aRetval.appendBezierSegment(
2057cdf0e10cSrcweir                             aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fScaledKappa),
2058cdf0e10cSrcweir                             aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fScaledKappa),
2059cdf0e10cSrcweir                             aSegEnd);
2060cdf0e10cSrcweir 
2061cdf0e10cSrcweir                         nSegment = (nSegment + 1) % nSegments;
2062cdf0e10cSrcweir                         aSegStart = aSegEnd;
2063cdf0e10cSrcweir                     }
2064cdf0e10cSrcweir 
2065cdf0e10cSrcweir                     // End in this sector
2066cdf0e10cSrcweir                     const double fSegStartRad(nSegment * fAnglePerSegment);
2067cdf0e10cSrcweir                     fFactor = fScaledKappa * ((fEnd - fSegStartRad) / fAnglePerSegment);
2068cdf0e10cSrcweir                     aSegEnd = B2DPoint(cos(fEnd), sin(fEnd));
2069cdf0e10cSrcweir 
2070cdf0e10cSrcweir                     aRetval.appendBezierSegment(
2071cdf0e10cSrcweir                         aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fFactor),
2072cdf0e10cSrcweir                         aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fFactor),
2073cdf0e10cSrcweir                         aSegEnd);
2074cdf0e10cSrcweir                 }
2075cdf0e10cSrcweir             }
2076cdf0e10cSrcweir 
2077cdf0e10cSrcweir 			// remove double points between segments created by segmented creation
2078cdf0e10cSrcweir 			aRetval.removeDoublePoints();
2079cdf0e10cSrcweir 
2080cdf0e10cSrcweir 			return aRetval;
2081cdf0e10cSrcweir 		}
2082cdf0e10cSrcweir 
createPolygonFromEllipseSegment(const B2DPoint & rCenter,double fRadiusX,double fRadiusY,double fStart,double fEnd)2083cdf0e10cSrcweir         B2DPolygon createPolygonFromEllipseSegment( const B2DPoint& rCenter, double fRadiusX, double fRadiusY, double fStart, double fEnd )
2084cdf0e10cSrcweir 		{
2085cdf0e10cSrcweir 	        B2DPolygon aRetval(createPolygonFromUnitEllipseSegment(fStart, fEnd));
2086cdf0e10cSrcweir 			const B2DHomMatrix aMatrix(createScaleTranslateB2DHomMatrix(fRadiusX, fRadiusY, rCenter.getX(), rCenter.getY()));
2087cdf0e10cSrcweir 
2088cdf0e10cSrcweir 			aRetval.transform(aMatrix);
2089cdf0e10cSrcweir 
2090cdf0e10cSrcweir 			return aRetval;
2091cdf0e10cSrcweir 		}
2092cdf0e10cSrcweir 
hasNeutralPoints(const B2DPolygon & rCandidate)2093cdf0e10cSrcweir 		bool hasNeutralPoints(const B2DPolygon& rCandidate)
2094cdf0e10cSrcweir 		{
2095cdf0e10cSrcweir 			OSL_ENSURE(!rCandidate.areControlPointsUsed(), "hasNeutralPoints: ATM works not for curves (!)");
2096cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
2097cdf0e10cSrcweir 
2098cdf0e10cSrcweir 			if(nPointCount > 2L)
2099cdf0e10cSrcweir 			{
2100cdf0e10cSrcweir 				B2DPoint aPrevPoint(rCandidate.getB2DPoint(nPointCount - 1L));
2101cdf0e10cSrcweir 				B2DPoint aCurrPoint(rCandidate.getB2DPoint(0L));
2102cdf0e10cSrcweir 
2103cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nPointCount; a++)
2104cdf0e10cSrcweir 				{
2105cdf0e10cSrcweir 					const B2DPoint aNextPoint(rCandidate.getB2DPoint((a + 1) % nPointCount));
2106cdf0e10cSrcweir 					const B2DVector aPrevVec(aPrevPoint - aCurrPoint);
2107cdf0e10cSrcweir 					const B2DVector aNextVec(aNextPoint - aCurrPoint);
2108cdf0e10cSrcweir 					const B2VectorOrientation aOrientation(getOrientation(aNextVec, aPrevVec));
2109cdf0e10cSrcweir 
2110cdf0e10cSrcweir 					if(ORIENTATION_NEUTRAL == aOrientation)
2111cdf0e10cSrcweir 					{
2112cdf0e10cSrcweir 						// current has neutral orientation
2113cdf0e10cSrcweir 						return true;
2114cdf0e10cSrcweir 					}
2115cdf0e10cSrcweir 					else
2116cdf0e10cSrcweir 					{
2117cdf0e10cSrcweir 						// prepare next
2118cdf0e10cSrcweir 						aPrevPoint = aCurrPoint;
2119cdf0e10cSrcweir 						aCurrPoint = aNextPoint;
2120cdf0e10cSrcweir 					}
2121cdf0e10cSrcweir 				}
2122cdf0e10cSrcweir 			}
2123cdf0e10cSrcweir 
2124cdf0e10cSrcweir 			return false;
2125cdf0e10cSrcweir 		}
2126cdf0e10cSrcweir 
removeNeutralPoints(const B2DPolygon & rCandidate)2127cdf0e10cSrcweir 		B2DPolygon removeNeutralPoints(const B2DPolygon& rCandidate)
2128cdf0e10cSrcweir 		{
2129cdf0e10cSrcweir 			if(hasNeutralPoints(rCandidate))
2130cdf0e10cSrcweir 			{
2131cdf0e10cSrcweir 				const sal_uInt32 nPointCount(rCandidate.count());
2132cdf0e10cSrcweir 				B2DPolygon aRetval;
2133cdf0e10cSrcweir 				B2DPoint aPrevPoint(rCandidate.getB2DPoint(nPointCount - 1L));
2134cdf0e10cSrcweir 				B2DPoint aCurrPoint(rCandidate.getB2DPoint(0L));
2135cdf0e10cSrcweir 
2136cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nPointCount; a++)
2137cdf0e10cSrcweir 				{
2138cdf0e10cSrcweir 					const B2DPoint aNextPoint(rCandidate.getB2DPoint((a + 1) % nPointCount));
2139cdf0e10cSrcweir 					const B2DVector aPrevVec(aPrevPoint - aCurrPoint);
2140cdf0e10cSrcweir 					const B2DVector aNextVec(aNextPoint - aCurrPoint);
2141cdf0e10cSrcweir 					const B2VectorOrientation aOrientation(getOrientation(aNextVec, aPrevVec));
2142cdf0e10cSrcweir 
2143cdf0e10cSrcweir 					if(ORIENTATION_NEUTRAL == aOrientation)
2144cdf0e10cSrcweir 					{
2145cdf0e10cSrcweir 						// current has neutral orientation, leave it out and prepare next
2146cdf0e10cSrcweir 						aCurrPoint = aNextPoint;
2147cdf0e10cSrcweir 					}
2148cdf0e10cSrcweir 					else
2149cdf0e10cSrcweir 					{
2150cdf0e10cSrcweir 						// add current point
2151cdf0e10cSrcweir 						aRetval.append(aCurrPoint);
2152cdf0e10cSrcweir 
2153cdf0e10cSrcweir 						// prepare next
2154cdf0e10cSrcweir 						aPrevPoint = aCurrPoint;
2155cdf0e10cSrcweir 						aCurrPoint = aNextPoint;
2156cdf0e10cSrcweir 					}
2157cdf0e10cSrcweir 				}
2158cdf0e10cSrcweir 
2159cdf0e10cSrcweir 				while(aRetval.count() && ORIENTATION_NEUTRAL == getOrientationForIndex(aRetval, 0L))
2160cdf0e10cSrcweir 				{
2161cdf0e10cSrcweir 					aRetval.remove(0L);
2162cdf0e10cSrcweir 				}
2163cdf0e10cSrcweir 
2164cdf0e10cSrcweir 				// copy closed state
2165cdf0e10cSrcweir 				aRetval.setClosed(rCandidate.isClosed());
2166cdf0e10cSrcweir 
2167cdf0e10cSrcweir 				return aRetval;
2168cdf0e10cSrcweir 			}
2169cdf0e10cSrcweir 			else
2170cdf0e10cSrcweir 			{
2171cdf0e10cSrcweir 				return rCandidate;
2172cdf0e10cSrcweir 			}
2173cdf0e10cSrcweir 		}
2174cdf0e10cSrcweir 
isConvex(const B2DPolygon & rCandidate)2175cdf0e10cSrcweir 		bool isConvex(const B2DPolygon& rCandidate)
2176cdf0e10cSrcweir 		{
2177cdf0e10cSrcweir 			OSL_ENSURE(!rCandidate.areControlPointsUsed(), "isConvex: ATM works not for curves (!)");
2178cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
2179cdf0e10cSrcweir 
2180cdf0e10cSrcweir 			if(nPointCount > 2L)
2181cdf0e10cSrcweir 			{
2182cdf0e10cSrcweir 				const B2DPoint aPrevPoint(rCandidate.getB2DPoint(nPointCount - 1L));
2183cdf0e10cSrcweir 				B2DPoint aCurrPoint(rCandidate.getB2DPoint(0L));
2184cdf0e10cSrcweir 				B2DVector aCurrVec(aPrevPoint - aCurrPoint);
2185cdf0e10cSrcweir 				B2VectorOrientation aOrientation(ORIENTATION_NEUTRAL);
2186cdf0e10cSrcweir 
2187cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nPointCount; a++)
2188cdf0e10cSrcweir 				{
2189cdf0e10cSrcweir 					const B2DPoint aNextPoint(rCandidate.getB2DPoint((a + 1) % nPointCount));
2190cdf0e10cSrcweir 					const B2DVector aNextVec(aNextPoint - aCurrPoint);
2191cdf0e10cSrcweir 					const B2VectorOrientation aCurrentOrientation(getOrientation(aNextVec, aCurrVec));
2192cdf0e10cSrcweir 
2193cdf0e10cSrcweir 					if(ORIENTATION_NEUTRAL == aOrientation)
2194cdf0e10cSrcweir 					{
2195cdf0e10cSrcweir 						// set start value, maybe neutral again
2196cdf0e10cSrcweir 						aOrientation = aCurrentOrientation;
2197cdf0e10cSrcweir 					}
2198cdf0e10cSrcweir 					else
2199cdf0e10cSrcweir 					{
2200cdf0e10cSrcweir 						if(ORIENTATION_NEUTRAL != aCurrentOrientation && aCurrentOrientation != aOrientation)
2201cdf0e10cSrcweir 						{
2202cdf0e10cSrcweir 							// different orientations found, that's it
2203cdf0e10cSrcweir 							return false;
2204cdf0e10cSrcweir 						}
2205cdf0e10cSrcweir 					}
2206cdf0e10cSrcweir 
2207cdf0e10cSrcweir 					// prepare next
2208cdf0e10cSrcweir 					aCurrPoint = aNextPoint;
2209cdf0e10cSrcweir 					aCurrVec = -aNextVec;
2210cdf0e10cSrcweir 				}
2211cdf0e10cSrcweir 			}
2212cdf0e10cSrcweir 
2213cdf0e10cSrcweir 			return true;
2214cdf0e10cSrcweir 		}
2215cdf0e10cSrcweir 
getOrientationForIndex(const B2DPolygon & rCandidate,sal_uInt32 nIndex)2216cdf0e10cSrcweir 		B2VectorOrientation getOrientationForIndex(const B2DPolygon& rCandidate, sal_uInt32 nIndex)
2217cdf0e10cSrcweir 		{
2218cdf0e10cSrcweir 			OSL_ENSURE(nIndex < rCandidate.count(), "getOrientationForIndex: index out of range (!)");
2219cdf0e10cSrcweir 			const B2DPoint aPrev(rCandidate.getB2DPoint(getIndexOfPredecessor(nIndex, rCandidate)));
2220cdf0e10cSrcweir 			const B2DPoint aCurr(rCandidate.getB2DPoint(nIndex));
2221cdf0e10cSrcweir 			const B2DPoint aNext(rCandidate.getB2DPoint(getIndexOfSuccessor(nIndex, rCandidate)));
2222cdf0e10cSrcweir 			const B2DVector aBack(aPrev - aCurr);
2223cdf0e10cSrcweir 			const B2DVector aForw(aNext - aCurr);
2224cdf0e10cSrcweir 
2225cdf0e10cSrcweir 			return getOrientation(aForw, aBack);
2226cdf0e10cSrcweir 		}
2227cdf0e10cSrcweir 
isPointOnLine(const B2DPoint & rStart,const B2DPoint & rEnd,const B2DPoint & rCandidate,bool bWithPoints)2228cdf0e10cSrcweir 		bool isPointOnLine(const B2DPoint& rStart, const B2DPoint& rEnd, const B2DPoint& rCandidate, bool bWithPoints)
2229cdf0e10cSrcweir 		{
2230cdf0e10cSrcweir 			if(rCandidate.equal(rStart) || rCandidate.equal(rEnd))
2231cdf0e10cSrcweir 			{
2232cdf0e10cSrcweir 				// candidate is in epsilon around start or end -> inside
2233cdf0e10cSrcweir 				return bWithPoints;
2234cdf0e10cSrcweir 			}
2235cdf0e10cSrcweir 			else if(rStart.equal(rEnd))
2236cdf0e10cSrcweir 			{
2237cdf0e10cSrcweir 				// start and end are equal, but candidate is outside their epsilon -> outside
2238cdf0e10cSrcweir 				return false;
2239cdf0e10cSrcweir 			}
2240cdf0e10cSrcweir 			else
2241cdf0e10cSrcweir 			{
2242cdf0e10cSrcweir 				const B2DVector aEdgeVector(rEnd - rStart);
2243cdf0e10cSrcweir 				const B2DVector aTestVector(rCandidate - rStart);
2244cdf0e10cSrcweir 
2245cdf0e10cSrcweir 				if(areParallel(aEdgeVector, aTestVector))
2246cdf0e10cSrcweir 				{
2247cdf0e10cSrcweir 					const double fZero(0.0);
2248cdf0e10cSrcweir 					const double fOne(1.0);
2249cdf0e10cSrcweir 					const double fParamTestOnCurr(fabs(aEdgeVector.getX()) > fabs(aEdgeVector.getY())
2250cdf0e10cSrcweir 						? aTestVector.getX() / aEdgeVector.getX()
2251cdf0e10cSrcweir 						: aTestVector.getY() / aEdgeVector.getY());
2252cdf0e10cSrcweir 
2253cdf0e10cSrcweir 					if(fTools::more(fParamTestOnCurr, fZero) && fTools::less(fParamTestOnCurr, fOne))
2254cdf0e10cSrcweir 					{
2255cdf0e10cSrcweir 						return true;
2256cdf0e10cSrcweir 					}
2257cdf0e10cSrcweir 				}
2258cdf0e10cSrcweir 
2259cdf0e10cSrcweir 				return false;
2260cdf0e10cSrcweir 			}
2261cdf0e10cSrcweir 		}
2262cdf0e10cSrcweir 
isPointOnPolygon(const B2DPolygon & rCandidate,const B2DPoint & rPoint,bool bWithPoints)2263cdf0e10cSrcweir 		bool isPointOnPolygon(const B2DPolygon& rCandidate, const B2DPoint& rPoint, bool bWithPoints)
2264cdf0e10cSrcweir 		{
2265cdf0e10cSrcweir 			const B2DPolygon aCandidate(rCandidate.areControlPointsUsed() ? rCandidate.getDefaultAdaptiveSubdivision() : rCandidate);
2266cdf0e10cSrcweir 			const sal_uInt32 nPointCount(aCandidate.count());
2267cdf0e10cSrcweir 
2268cdf0e10cSrcweir 			if(nPointCount > 1L)
2269cdf0e10cSrcweir 			{
2270cdf0e10cSrcweir 				const sal_uInt32 nLoopCount(aCandidate.isClosed() ? nPointCount : nPointCount - 1L);
2271cdf0e10cSrcweir 				B2DPoint aCurrentPoint(aCandidate.getB2DPoint(0L));
2272cdf0e10cSrcweir 
2273cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nLoopCount; a++)
2274cdf0e10cSrcweir 				{
2275cdf0e10cSrcweir 					const B2DPoint aNextPoint(aCandidate.getB2DPoint((a + 1L) % nPointCount));
2276cdf0e10cSrcweir 
2277cdf0e10cSrcweir 					if(isPointOnLine(aCurrentPoint, aNextPoint, rPoint, bWithPoints))
2278cdf0e10cSrcweir 					{
2279cdf0e10cSrcweir 						return true;
2280cdf0e10cSrcweir 					}
2281cdf0e10cSrcweir 
2282cdf0e10cSrcweir 					aCurrentPoint = aNextPoint;
2283cdf0e10cSrcweir 				}
2284cdf0e10cSrcweir 			}
2285cdf0e10cSrcweir 			else if(nPointCount && bWithPoints)
2286cdf0e10cSrcweir 			{
2287cdf0e10cSrcweir 				return rPoint.equal(aCandidate.getB2DPoint(0L));
2288cdf0e10cSrcweir 			}
2289cdf0e10cSrcweir 
2290cdf0e10cSrcweir 			return false;
2291cdf0e10cSrcweir 		}
2292cdf0e10cSrcweir 
isPointInTriangle(const B2DPoint & rA,const B2DPoint & rB,const B2DPoint & rC,const B2DPoint & rCandidate,bool bWithBorder)2293cdf0e10cSrcweir 		bool isPointInTriangle(const B2DPoint& rA, const B2DPoint& rB, const B2DPoint& rC, const B2DPoint& rCandidate, bool bWithBorder)
2294cdf0e10cSrcweir 		{
2295cdf0e10cSrcweir 			if(arePointsOnSameSideOfLine(rA, rB, rC, rCandidate, bWithBorder))
2296cdf0e10cSrcweir 			{
2297cdf0e10cSrcweir 				if(arePointsOnSameSideOfLine(rB, rC, rA, rCandidate, bWithBorder))
2298cdf0e10cSrcweir 				{
2299cdf0e10cSrcweir 					if(arePointsOnSameSideOfLine(rC, rA, rB, rCandidate, bWithBorder))
2300cdf0e10cSrcweir 					{
2301cdf0e10cSrcweir 						return true;
2302cdf0e10cSrcweir 					}
2303cdf0e10cSrcweir 				}
2304cdf0e10cSrcweir 			}
2305cdf0e10cSrcweir 
2306cdf0e10cSrcweir 			return false;
2307cdf0e10cSrcweir 		}
2308cdf0e10cSrcweir 
arePointsOnSameSideOfLine(const B2DPoint & rStart,const B2DPoint & rEnd,const B2DPoint & rCandidateA,const B2DPoint & rCandidateB,bool bWithLine)2309cdf0e10cSrcweir 		bool arePointsOnSameSideOfLine(const B2DPoint& rStart, const B2DPoint& rEnd, const B2DPoint& rCandidateA, const B2DPoint& rCandidateB, bool bWithLine)
2310cdf0e10cSrcweir 		{
2311cdf0e10cSrcweir 			const B2DVector aLineVector(rEnd - rStart);
2312cdf0e10cSrcweir 			const B2DVector aVectorToA(rEnd - rCandidateA);
2313cdf0e10cSrcweir 			const double fCrossA(aLineVector.cross(aVectorToA));
2314cdf0e10cSrcweir 
2315cdf0e10cSrcweir 			if(fTools::equalZero(fCrossA))
2316cdf0e10cSrcweir 			{
2317cdf0e10cSrcweir 				// one point on the line
2318cdf0e10cSrcweir 				return bWithLine;
2319cdf0e10cSrcweir 			}
2320cdf0e10cSrcweir 
2321cdf0e10cSrcweir 			const B2DVector aVectorToB(rEnd - rCandidateB);
2322cdf0e10cSrcweir 			const double fCrossB(aLineVector.cross(aVectorToB));
2323cdf0e10cSrcweir 
2324cdf0e10cSrcweir 			if(fTools::equalZero(fCrossB))
2325cdf0e10cSrcweir 			{
2326cdf0e10cSrcweir 				// one point on the line
2327cdf0e10cSrcweir 				return bWithLine;
2328cdf0e10cSrcweir 			}
2329cdf0e10cSrcweir 
2330cdf0e10cSrcweir 			// return true if they both have the same sign
2331cdf0e10cSrcweir 			return ((fCrossA > 0.0) == (fCrossB > 0.0));
2332cdf0e10cSrcweir 		}
2333cdf0e10cSrcweir 
addTriangleFan(const B2DPolygon & rCandidate,B2DPolygon & rTarget)2334cdf0e10cSrcweir 		void addTriangleFan(const B2DPolygon& rCandidate, B2DPolygon& rTarget)
2335cdf0e10cSrcweir 		{
2336cdf0e10cSrcweir 			const sal_uInt32 nCount(rCandidate.count());
2337cdf0e10cSrcweir 
2338cdf0e10cSrcweir 			if(nCount > 2L)
2339cdf0e10cSrcweir 			{
2340cdf0e10cSrcweir 				const B2DPoint aStart(rCandidate.getB2DPoint(0L));
2341cdf0e10cSrcweir 				B2DPoint aLast(rCandidate.getB2DPoint(1L));
2342cdf0e10cSrcweir 
2343cdf0e10cSrcweir 				for(sal_uInt32 a(2L); a < nCount; a++)
2344cdf0e10cSrcweir 				{
2345cdf0e10cSrcweir 					const B2DPoint aCurrent(rCandidate.getB2DPoint(a));
2346cdf0e10cSrcweir 					rTarget.append(aStart);
2347cdf0e10cSrcweir 					rTarget.append(aLast);
2348cdf0e10cSrcweir 					rTarget.append(aCurrent);
2349cdf0e10cSrcweir 
2350cdf0e10cSrcweir 					// prepare next
2351cdf0e10cSrcweir 					aLast = aCurrent;
2352cdf0e10cSrcweir 				}
2353cdf0e10cSrcweir 			}
2354cdf0e10cSrcweir 		}
2355cdf0e10cSrcweir 
2356cdf0e10cSrcweir         namespace
2357cdf0e10cSrcweir         {
2358cdf0e10cSrcweir             /// return 0 for input of 0, -1 for negative and 1 for positive input
lcl_sgn(const double n)2359cdf0e10cSrcweir             inline int lcl_sgn( const double n )
2360cdf0e10cSrcweir             {
2361cdf0e10cSrcweir                 return n == 0.0 ? 0 : 1 - 2*::rtl::math::isSignBitSet(n);
2362cdf0e10cSrcweir             }
2363cdf0e10cSrcweir         }
2364cdf0e10cSrcweir 
isRectangle(const B2DPolygon & rPoly)2365cdf0e10cSrcweir         bool isRectangle( const B2DPolygon& rPoly )
2366cdf0e10cSrcweir         {
2367cdf0e10cSrcweir             // polygon must be closed to resemble a rect, and contain
2368cdf0e10cSrcweir             // at least four points.
2369cdf0e10cSrcweir             if( !rPoly.isClosed() ||
2370cdf0e10cSrcweir                 rPoly.count() < 4 ||
2371cdf0e10cSrcweir                 rPoly.areControlPointsUsed() )
2372cdf0e10cSrcweir             {
2373cdf0e10cSrcweir                 return false;
2374cdf0e10cSrcweir             }
2375cdf0e10cSrcweir 
2376cdf0e10cSrcweir             // number of 90 degree turns the polygon has taken
2377cdf0e10cSrcweir             int nNumTurns(0);
2378cdf0e10cSrcweir 
2379cdf0e10cSrcweir             int  nVerticalEdgeType=0;
2380cdf0e10cSrcweir             int  nHorizontalEdgeType=0;
2381cdf0e10cSrcweir             bool bNullVertex(true);
2382cdf0e10cSrcweir             bool bCWPolygon(false);  // when true, polygon is CW
2383cdf0e10cSrcweir                                      // oriented, when false, CCW
2384cdf0e10cSrcweir             bool bOrientationSet(false); // when false, polygon
2385cdf0e10cSrcweir                                          // orientation has not yet
2386cdf0e10cSrcweir                                          // been determined.
2387cdf0e10cSrcweir 
2388cdf0e10cSrcweir             // scan all _edges_ (which involves coming back to point 0
2389cdf0e10cSrcweir             // for the last edge - thus the modulo operation below)
2390cdf0e10cSrcweir             const sal_Int32 nCount( rPoly.count() );
2391cdf0e10cSrcweir             for( sal_Int32 i=0; i<nCount; ++i )
2392cdf0e10cSrcweir             {
2393cdf0e10cSrcweir                 const B2DPoint& rPoint0( rPoly.getB2DPoint(i % nCount) );
2394cdf0e10cSrcweir                 const B2DPoint& rPoint1( rPoly.getB2DPoint((i+1) % nCount) );
2395cdf0e10cSrcweir 
2396cdf0e10cSrcweir                 // is 0 for zero direction vector, 1 for south edge and -1
2397cdf0e10cSrcweir                 // for north edge (standard screen coordinate system)
2398cdf0e10cSrcweir                 int nCurrVerticalEdgeType( lcl_sgn( rPoint1.getY() - rPoint0.getY() ) );
2399cdf0e10cSrcweir 
2400cdf0e10cSrcweir                 // is 0 for zero direction vector, 1 for east edge and -1
2401cdf0e10cSrcweir                 // for west edge (standard screen coordinate system)
2402cdf0e10cSrcweir                 int nCurrHorizontalEdgeType( lcl_sgn(rPoint1.getX() - rPoint0.getX()) );
2403cdf0e10cSrcweir 
2404cdf0e10cSrcweir                 if( nCurrVerticalEdgeType && nCurrHorizontalEdgeType )
2405cdf0e10cSrcweir                     return false; // oblique edge - for sure no rect
2406cdf0e10cSrcweir 
2407cdf0e10cSrcweir                 const bool bCurrNullVertex( !nCurrVerticalEdgeType && !nCurrHorizontalEdgeType );
2408cdf0e10cSrcweir 
2409cdf0e10cSrcweir                 // current vertex is equal to previous - just skip,
2410cdf0e10cSrcweir                 // until we have a real edge
2411cdf0e10cSrcweir                 if( bCurrNullVertex )
2412cdf0e10cSrcweir                     continue;
2413cdf0e10cSrcweir 
2414cdf0e10cSrcweir                 // if previous edge has two identical points, because
2415cdf0e10cSrcweir                 // no previous edge direction was available, simply
2416cdf0e10cSrcweir                 // take this first non-null edge as the start
2417cdf0e10cSrcweir                 // direction. That's what will happen here, if
2418cdf0e10cSrcweir                 // bNullVertex is false
2419cdf0e10cSrcweir                 if( !bNullVertex )
2420cdf0e10cSrcweir                 {
2421cdf0e10cSrcweir                     // 2D cross product - is 1 for CW and -1 for CCW turns
2422cdf0e10cSrcweir                     const int nCrossProduct( nHorizontalEdgeType*nCurrVerticalEdgeType -
2423cdf0e10cSrcweir                                              nVerticalEdgeType*nCurrHorizontalEdgeType );
2424cdf0e10cSrcweir 
2425cdf0e10cSrcweir                     if( !nCrossProduct )
2426cdf0e10cSrcweir                         continue; // no change in orientation -
2427cdf0e10cSrcweir                                   // collinear edges - just go on
2428cdf0e10cSrcweir 
2429cdf0e10cSrcweir                     // if polygon orientation is not set, we'll
2430cdf0e10cSrcweir                     // determine it now
2431cdf0e10cSrcweir                     if( !bOrientationSet )
2432cdf0e10cSrcweir                     {
2433cdf0e10cSrcweir                         bCWPolygon = nCrossProduct == 1;
2434cdf0e10cSrcweir                         bOrientationSet = true;
2435cdf0e10cSrcweir                     }
2436cdf0e10cSrcweir                     else
2437cdf0e10cSrcweir                     {
2438cdf0e10cSrcweir                         // if current turn orientation is not equal
2439cdf0e10cSrcweir                         // initial orientation, this is not a
2440cdf0e10cSrcweir                         // rectangle (as rectangles have consistent
2441cdf0e10cSrcweir                         // orientation).
2442cdf0e10cSrcweir                         if( (nCrossProduct == 1) != bCWPolygon )
2443cdf0e10cSrcweir                             return false;
2444cdf0e10cSrcweir                     }
2445cdf0e10cSrcweir 
2446cdf0e10cSrcweir                     ++nNumTurns;
2447cdf0e10cSrcweir 
2448cdf0e10cSrcweir                     // More than four 90 degree turns are an
2449cdf0e10cSrcweir                     // indication that this must not be a rectangle.
2450cdf0e10cSrcweir                     if( nNumTurns > 4 )
2451cdf0e10cSrcweir                         return false;
2452cdf0e10cSrcweir                 }
2453cdf0e10cSrcweir 
2454cdf0e10cSrcweir                 // store current state for the next turn
2455cdf0e10cSrcweir                 nVerticalEdgeType	= nCurrVerticalEdgeType;
2456cdf0e10cSrcweir                 nHorizontalEdgeType = nCurrHorizontalEdgeType;
2457cdf0e10cSrcweir                 bNullVertex		    = false; // won't reach this line,
2458cdf0e10cSrcweir                                              // if bCurrNullVertex is
2459cdf0e10cSrcweir                                              // true - see above
2460cdf0e10cSrcweir             }
2461cdf0e10cSrcweir 
2462cdf0e10cSrcweir             return true;
2463cdf0e10cSrcweir         }
2464cdf0e10cSrcweir 
createB3DPolygonFromB2DPolygon(const B2DPolygon & rCandidate,double fZCoordinate)2465cdf0e10cSrcweir 		B3DPolygon createB3DPolygonFromB2DPolygon(const B2DPolygon& rCandidate, double fZCoordinate)
2466cdf0e10cSrcweir 		{
2467cdf0e10cSrcweir 			if(rCandidate.areControlPointsUsed())
2468cdf0e10cSrcweir 			{
2469cdf0e10cSrcweir 				// call myself recursively with subdivided input
2470cdf0e10cSrcweir 				const B2DPolygon aCandidate(adaptiveSubdivideByAngle(rCandidate));
2471cdf0e10cSrcweir 				return createB3DPolygonFromB2DPolygon(aCandidate, fZCoordinate);
2472cdf0e10cSrcweir 			}
2473cdf0e10cSrcweir 			else
2474cdf0e10cSrcweir 			{
2475cdf0e10cSrcweir 				B3DPolygon aRetval;
2476cdf0e10cSrcweir 
2477cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
2478cdf0e10cSrcweir 				{
2479cdf0e10cSrcweir 					B2DPoint aPoint(rCandidate.getB2DPoint(a));
2480cdf0e10cSrcweir 					aRetval.append(B3DPoint(aPoint.getX(), aPoint.getY(), fZCoordinate));
2481cdf0e10cSrcweir 				}
2482cdf0e10cSrcweir 
2483cdf0e10cSrcweir 				// copy closed state
2484cdf0e10cSrcweir 				aRetval.setClosed(rCandidate.isClosed());
2485cdf0e10cSrcweir 
2486cdf0e10cSrcweir 				return aRetval;
2487cdf0e10cSrcweir 			}
2488cdf0e10cSrcweir 		}
2489cdf0e10cSrcweir 
createB2DPolygonFromB3DPolygon(const B3DPolygon & rCandidate,const B3DHomMatrix & rMat)2490cdf0e10cSrcweir 		B2DPolygon createB2DPolygonFromB3DPolygon(const B3DPolygon& rCandidate, const B3DHomMatrix& rMat)
2491cdf0e10cSrcweir 		{
2492cdf0e10cSrcweir 			B2DPolygon aRetval;
2493cdf0e10cSrcweir 			const sal_uInt32 nCount(rCandidate.count());
2494cdf0e10cSrcweir 			const bool bIsIdentity(rMat.isIdentity());
2495cdf0e10cSrcweir 
2496cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < nCount; a++)
2497cdf0e10cSrcweir 			{
2498cdf0e10cSrcweir 				B3DPoint aCandidate(rCandidate.getB3DPoint(a));
2499cdf0e10cSrcweir 
2500cdf0e10cSrcweir 				if(!bIsIdentity)
2501cdf0e10cSrcweir 				{
2502cdf0e10cSrcweir 					aCandidate *= rMat;
2503cdf0e10cSrcweir 				}
2504cdf0e10cSrcweir 
2505cdf0e10cSrcweir 				aRetval.append(B2DPoint(aCandidate.getX(), aCandidate.getY()));
2506cdf0e10cSrcweir 			}
2507cdf0e10cSrcweir 
2508cdf0e10cSrcweir 			// copy closed state
2509cdf0e10cSrcweir 			aRetval.setClosed(rCandidate.isClosed());
2510cdf0e10cSrcweir 
2511cdf0e10cSrcweir 			return aRetval;
2512cdf0e10cSrcweir 		}
2513cdf0e10cSrcweir 
getDistancePointToEndlessRay(const B2DPoint & rPointA,const B2DPoint & rPointB,const B2DPoint & rTestPoint,double & rCut)2514cdf0e10cSrcweir 		double getDistancePointToEndlessRay(const B2DPoint& rPointA, const B2DPoint& rPointB, const B2DPoint& rTestPoint, double& rCut)
2515cdf0e10cSrcweir 		{
2516cdf0e10cSrcweir 			if(rPointA.equal(rPointB))
2517cdf0e10cSrcweir 			{
2518cdf0e10cSrcweir 				rCut = 0.0;
2519cdf0e10cSrcweir 				const B2DVector aVector(rTestPoint - rPointA);
2520cdf0e10cSrcweir 				return aVector.getLength();
2521cdf0e10cSrcweir 			}
2522cdf0e10cSrcweir 			else
2523cdf0e10cSrcweir 			{
2524cdf0e10cSrcweir 				// get the relative cut value on line vector (Vector1) for cut with perpendicular through TestPoint
2525cdf0e10cSrcweir 				const B2DVector aVector1(rPointB - rPointA);
2526cdf0e10cSrcweir 				const B2DVector aVector2(rTestPoint - rPointA);
2527cdf0e10cSrcweir 				const double fDividend((aVector2.getX() * aVector1.getX()) + (aVector2.getY() * aVector1.getY()));
2528cdf0e10cSrcweir 				const double fDivisor((aVector1.getX() * aVector1.getX()) + (aVector1.getY() * aVector1.getY()));
2529cdf0e10cSrcweir 
2530cdf0e10cSrcweir                 rCut = fDividend / fDivisor;
2531cdf0e10cSrcweir 
2532cdf0e10cSrcweir 				const B2DPoint aCutPoint(rPointA + rCut * aVector1);
2533cdf0e10cSrcweir 				const B2DVector aVector(rTestPoint - aCutPoint);
2534cdf0e10cSrcweir 				return aVector.getLength();
2535cdf0e10cSrcweir 			}
2536cdf0e10cSrcweir 		}
2537cdf0e10cSrcweir 
getSmallestDistancePointToEdge(const B2DPoint & rPointA,const B2DPoint & rPointB,const B2DPoint & rTestPoint,double & rCut)2538cdf0e10cSrcweir 		double getSmallestDistancePointToEdge(const B2DPoint& rPointA, const B2DPoint& rPointB, const B2DPoint& rTestPoint, double& rCut)
2539cdf0e10cSrcweir 		{
2540cdf0e10cSrcweir 			if(rPointA.equal(rPointB))
2541cdf0e10cSrcweir 			{
2542cdf0e10cSrcweir 				rCut = 0.0;
2543cdf0e10cSrcweir 				const B2DVector aVector(rTestPoint - rPointA);
2544cdf0e10cSrcweir 				return aVector.getLength();
2545cdf0e10cSrcweir 			}
2546cdf0e10cSrcweir 			else
2547cdf0e10cSrcweir 			{
2548cdf0e10cSrcweir 				// get the relative cut value on line vector (Vector1) for cut with perpendicular through TestPoint
2549cdf0e10cSrcweir 				const B2DVector aVector1(rPointB - rPointA);
2550cdf0e10cSrcweir 				const B2DVector aVector2(rTestPoint - rPointA);
2551cdf0e10cSrcweir 				const double fDividend((aVector2.getX() * aVector1.getX()) + (aVector2.getY() * aVector1.getY()));
2552cdf0e10cSrcweir 				const double fDivisor((aVector1.getX() * aVector1.getX()) + (aVector1.getY() * aVector1.getY()));
2553cdf0e10cSrcweir 				const double fCut(fDividend / fDivisor);
2554cdf0e10cSrcweir 
2555cdf0e10cSrcweir 				if(fCut < 0.0)
2556cdf0e10cSrcweir 				{
2557cdf0e10cSrcweir 					// not in line range, get distance to PointA
2558cdf0e10cSrcweir 					rCut = 0.0;
2559cdf0e10cSrcweir 					return aVector2.getLength();
2560cdf0e10cSrcweir 				}
2561cdf0e10cSrcweir 				else if(fCut > 1.0)
2562cdf0e10cSrcweir 				{
2563cdf0e10cSrcweir 					// not in line range, get distance to PointB
2564cdf0e10cSrcweir 					rCut = 1.0;
2565cdf0e10cSrcweir 					const B2DVector aVector(rTestPoint - rPointB);
2566cdf0e10cSrcweir 					return aVector.getLength();
2567cdf0e10cSrcweir 				}
2568cdf0e10cSrcweir 				else
2569cdf0e10cSrcweir 				{
2570cdf0e10cSrcweir 					// in line range
2571cdf0e10cSrcweir 					const B2DPoint aCutPoint(rPointA + fCut * aVector1);
2572cdf0e10cSrcweir 					const B2DVector aVector(rTestPoint - aCutPoint);
2573cdf0e10cSrcweir 					rCut = fCut;
2574cdf0e10cSrcweir 					return aVector.getLength();
2575cdf0e10cSrcweir 				}
2576cdf0e10cSrcweir 			}
2577cdf0e10cSrcweir 		}
2578cdf0e10cSrcweir 
getSmallestDistancePointToPolygon(const B2DPolygon & rCandidate,const B2DPoint & rTestPoint,sal_uInt32 & rEdgeIndex,double & rCut)2579cdf0e10cSrcweir 		double getSmallestDistancePointToPolygon(const B2DPolygon& rCandidate, const B2DPoint& rTestPoint, sal_uInt32& rEdgeIndex, double& rCut)
2580cdf0e10cSrcweir 		{
2581cdf0e10cSrcweir 			double fRetval(DBL_MAX);
2582cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
2583cdf0e10cSrcweir 
2584cdf0e10cSrcweir 			if(nPointCount > 1L)
2585cdf0e10cSrcweir 			{
2586cdf0e10cSrcweir 				const double fZero(0.0);
2587cdf0e10cSrcweir 				const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
2588cdf0e10cSrcweir 				B2DCubicBezier aBezier;
2589cdf0e10cSrcweir 				aBezier.setStartPoint(rCandidate.getB2DPoint(0));
2590cdf0e10cSrcweir 
2591cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nEdgeCount; a++)
2592cdf0e10cSrcweir 				{
2593cdf0e10cSrcweir 					const sal_uInt32 nNextIndex((a + 1) % nPointCount);
2594cdf0e10cSrcweir 					aBezier.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
2595cdf0e10cSrcweir 					double fEdgeDist;
2596cdf0e10cSrcweir 					double fNewCut;
2597cdf0e10cSrcweir 					bool bEdgeIsCurve(false);
2598cdf0e10cSrcweir 
2599cdf0e10cSrcweir 					if(rCandidate.areControlPointsUsed())
2600cdf0e10cSrcweir 					{
2601cdf0e10cSrcweir 						aBezier.setControlPointA(rCandidate.getNextControlPoint(a));
2602cdf0e10cSrcweir 						aBezier.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
2603cdf0e10cSrcweir 						aBezier.testAndSolveTrivialBezier();
2604cdf0e10cSrcweir 						bEdgeIsCurve = aBezier.isBezier();
2605cdf0e10cSrcweir 					}
2606cdf0e10cSrcweir 
2607cdf0e10cSrcweir 					if(bEdgeIsCurve)
2608cdf0e10cSrcweir 					{
2609cdf0e10cSrcweir 						fEdgeDist = aBezier.getSmallestDistancePointToBezierSegment(rTestPoint, fNewCut);
2610cdf0e10cSrcweir 					}
2611cdf0e10cSrcweir 					else
2612cdf0e10cSrcweir 					{
2613cdf0e10cSrcweir 						fEdgeDist = getSmallestDistancePointToEdge(aBezier.getStartPoint(), aBezier.getEndPoint(), rTestPoint, fNewCut);
2614cdf0e10cSrcweir 					}
2615cdf0e10cSrcweir 
2616cdf0e10cSrcweir 					if(DBL_MAX == fRetval || fEdgeDist < fRetval)
2617cdf0e10cSrcweir 					{
2618cdf0e10cSrcweir 						fRetval = fEdgeDist;
2619cdf0e10cSrcweir 						rEdgeIndex = a;
2620cdf0e10cSrcweir 						rCut = fNewCut;
2621cdf0e10cSrcweir 
2622cdf0e10cSrcweir 						if(fTools::equal(fRetval, fZero))
2623cdf0e10cSrcweir 						{
2624cdf0e10cSrcweir 							// already found zero distance, cannot get better. Ensure numerical zero value and end loop.
2625cdf0e10cSrcweir 							fRetval = 0.0;
2626cdf0e10cSrcweir 							break;
2627cdf0e10cSrcweir 						}
2628cdf0e10cSrcweir 					}
2629cdf0e10cSrcweir 
2630cdf0e10cSrcweir 					// prepare next step
2631cdf0e10cSrcweir 					aBezier.setStartPoint(aBezier.getEndPoint());
2632cdf0e10cSrcweir 				}
2633cdf0e10cSrcweir 
2634cdf0e10cSrcweir 				if(1.0 == rCut)
2635cdf0e10cSrcweir 				{
2636cdf0e10cSrcweir 					// correct rEdgeIndex when not last point
2637cdf0e10cSrcweir 					if(rCandidate.isClosed())
2638cdf0e10cSrcweir 					{
2639cdf0e10cSrcweir 						rEdgeIndex = getIndexOfSuccessor(rEdgeIndex, rCandidate);
2640cdf0e10cSrcweir 						rCut = 0.0;
2641cdf0e10cSrcweir 					}
2642cdf0e10cSrcweir 					else
2643cdf0e10cSrcweir 					{
2644cdf0e10cSrcweir 						if(rEdgeIndex != nEdgeCount - 1L)
2645cdf0e10cSrcweir 						{
2646cdf0e10cSrcweir 							rEdgeIndex++;
2647cdf0e10cSrcweir 							rCut = 0.0;
2648cdf0e10cSrcweir 						}
2649cdf0e10cSrcweir 					}
2650cdf0e10cSrcweir 				}
2651cdf0e10cSrcweir 			}
2652cdf0e10cSrcweir 
2653cdf0e10cSrcweir 			return fRetval;
2654cdf0e10cSrcweir 		}
2655cdf0e10cSrcweir 
distort(const B2DPoint & rCandidate,const B2DRange & rOriginal,const B2DPoint & rTopLeft,const B2DPoint & rTopRight,const B2DPoint & rBottomLeft,const B2DPoint & rBottomRight)2656cdf0e10cSrcweir 		B2DPoint distort(const B2DPoint& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight)
2657cdf0e10cSrcweir 		{
2658cdf0e10cSrcweir 			if(fTools::equalZero(rOriginal.getWidth()) || fTools::equalZero(rOriginal.getHeight()))
2659cdf0e10cSrcweir 			{
2660cdf0e10cSrcweir 				return rCandidate;
2661cdf0e10cSrcweir 			}
2662cdf0e10cSrcweir 			else
2663cdf0e10cSrcweir 			{
2664cdf0e10cSrcweir 				const double fRelativeX((rCandidate.getX() - rOriginal.getMinX()) / rOriginal.getWidth());
2665cdf0e10cSrcweir 				const double fRelativeY((rCandidate.getY() - rOriginal.getMinY()) / rOriginal.getHeight());
2666cdf0e10cSrcweir 				const double fOneMinusRelativeX(1.0 - fRelativeX);
2667cdf0e10cSrcweir 				const double fOneMinusRelativeY(1.0 - fRelativeY);
2668cdf0e10cSrcweir 				const double fNewX((fOneMinusRelativeY) * ((fOneMinusRelativeX) * rTopLeft.getX() + fRelativeX * rTopRight.getX()) +
2669cdf0e10cSrcweir 					fRelativeY * ((fOneMinusRelativeX) * rBottomLeft.getX() + fRelativeX * rBottomRight.getX()));
2670cdf0e10cSrcweir 				const double fNewY((fOneMinusRelativeX) * ((fOneMinusRelativeY) * rTopLeft.getY() + fRelativeY * rBottomLeft.getY()) +
2671cdf0e10cSrcweir 					fRelativeX * ((fOneMinusRelativeY) * rTopRight.getY() + fRelativeY * rBottomRight.getY()));
2672cdf0e10cSrcweir 
2673cdf0e10cSrcweir 				return B2DPoint(fNewX, fNewY);
2674cdf0e10cSrcweir 			}
2675cdf0e10cSrcweir 		}
2676cdf0e10cSrcweir 
distort(const B2DPolygon & rCandidate,const B2DRange & rOriginal,const B2DPoint & rTopLeft,const B2DPoint & rTopRight,const B2DPoint & rBottomLeft,const B2DPoint & rBottomRight)2677cdf0e10cSrcweir 		B2DPolygon distort(const B2DPolygon& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight)
2678cdf0e10cSrcweir 		{
2679cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
2680cdf0e10cSrcweir 
2681cdf0e10cSrcweir 			if(nPointCount && 0.0 != rOriginal.getWidth() && 0.0 != rOriginal.getHeight())
2682cdf0e10cSrcweir 			{
2683cdf0e10cSrcweir 				B2DPolygon aRetval;
2684cdf0e10cSrcweir 
2685cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nPointCount; a++)
2686cdf0e10cSrcweir 				{
2687cdf0e10cSrcweir 					aRetval.append(distort(rCandidate.getB2DPoint(a), rOriginal, rTopLeft, rTopRight, rBottomLeft, rBottomRight));
2688cdf0e10cSrcweir 
2689cdf0e10cSrcweir 					if(rCandidate.areControlPointsUsed())
2690cdf0e10cSrcweir 					{
2691cdf0e10cSrcweir 						if(!rCandidate.getPrevControlPoint(a).equalZero())
2692cdf0e10cSrcweir 						{
2693cdf0e10cSrcweir 							aRetval.setPrevControlPoint(a, distort(rCandidate.getPrevControlPoint(a), rOriginal, rTopLeft, rTopRight, rBottomLeft, rBottomRight));
2694cdf0e10cSrcweir 						}
2695cdf0e10cSrcweir 
2696cdf0e10cSrcweir 						if(!rCandidate.getNextControlPoint(a).equalZero())
2697cdf0e10cSrcweir 						{
2698cdf0e10cSrcweir 							aRetval.setNextControlPoint(a, distort(rCandidate.getNextControlPoint(a), rOriginal, rTopLeft, rTopRight, rBottomLeft, rBottomRight));
2699cdf0e10cSrcweir 						}
2700cdf0e10cSrcweir 					}
2701cdf0e10cSrcweir 				}
2702cdf0e10cSrcweir 
2703cdf0e10cSrcweir 				aRetval.setClosed(rCandidate.isClosed());
2704cdf0e10cSrcweir 				return aRetval;
2705cdf0e10cSrcweir 			}
2706cdf0e10cSrcweir 			else
2707cdf0e10cSrcweir 			{
2708cdf0e10cSrcweir 				return rCandidate;
2709cdf0e10cSrcweir 			}
2710cdf0e10cSrcweir 		}
2711cdf0e10cSrcweir 
rotateAroundPoint(const B2DPolygon & rCandidate,const B2DPoint & rCenter,double fAngle)2712cdf0e10cSrcweir 		B2DPolygon rotateAroundPoint(const B2DPolygon& rCandidate, const B2DPoint& rCenter, double fAngle)
2713cdf0e10cSrcweir 		{
2714cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
2715cdf0e10cSrcweir 			B2DPolygon aRetval(rCandidate);
2716cdf0e10cSrcweir 
2717cdf0e10cSrcweir 			if(nPointCount)
2718cdf0e10cSrcweir 			{
2719cdf0e10cSrcweir                 const B2DHomMatrix aMatrix(basegfx::tools::createRotateAroundPoint(rCenter, fAngle));
2720cdf0e10cSrcweir 
2721cdf0e10cSrcweir                 aRetval.transform(aMatrix);
2722cdf0e10cSrcweir 			}
2723cdf0e10cSrcweir 
2724cdf0e10cSrcweir 			return aRetval;
2725cdf0e10cSrcweir 		}
2726cdf0e10cSrcweir 
expandToCurve(const B2DPolygon & rCandidate)2727cdf0e10cSrcweir 		B2DPolygon expandToCurve(const B2DPolygon& rCandidate)
2728cdf0e10cSrcweir 		{
2729cdf0e10cSrcweir 			B2DPolygon aRetval(rCandidate);
2730cdf0e10cSrcweir 
2731cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
2732cdf0e10cSrcweir 			{
2733cdf0e10cSrcweir 				expandToCurveInPoint(aRetval, a);
2734cdf0e10cSrcweir 			}
2735cdf0e10cSrcweir 
2736cdf0e10cSrcweir 			return aRetval;
2737cdf0e10cSrcweir 		}
2738cdf0e10cSrcweir 
expandToCurveInPoint(B2DPolygon & rCandidate,sal_uInt32 nIndex)2739cdf0e10cSrcweir 		bool expandToCurveInPoint(B2DPolygon& rCandidate, sal_uInt32 nIndex)
2740cdf0e10cSrcweir 		{
2741cdf0e10cSrcweir 			OSL_ENSURE(nIndex < rCandidate.count(), "expandToCurveInPoint: Access to polygon out of range (!)");
2742cdf0e10cSrcweir 			bool bRetval(false);
2743cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
2744cdf0e10cSrcweir 
2745cdf0e10cSrcweir 			if(nPointCount)
2746cdf0e10cSrcweir 			{
2747cdf0e10cSrcweir 				// predecessor
2748cdf0e10cSrcweir 				if(!rCandidate.isPrevControlPointUsed(nIndex))
2749cdf0e10cSrcweir 				{
2750cdf0e10cSrcweir 					if(!rCandidate.isClosed() && 0 == nIndex)
2751cdf0e10cSrcweir 					{
2752cdf0e10cSrcweir 						// do not create previous vector for start point of open polygon
2753cdf0e10cSrcweir 					}
2754cdf0e10cSrcweir 					else
2755cdf0e10cSrcweir 					{
2756cdf0e10cSrcweir 						const sal_uInt32 nPrevIndex((nIndex + (nPointCount - 1)) % nPointCount);
2757cdf0e10cSrcweir 						rCandidate.setPrevControlPoint(nIndex, interpolate(rCandidate.getB2DPoint(nIndex), rCandidate.getB2DPoint(nPrevIndex), 1.0 / 3.0));
2758cdf0e10cSrcweir 						bRetval = true;
2759cdf0e10cSrcweir 					}
2760cdf0e10cSrcweir 				}
2761cdf0e10cSrcweir 
2762cdf0e10cSrcweir 				// successor
2763cdf0e10cSrcweir 				if(!rCandidate.isNextControlPointUsed(nIndex))
2764cdf0e10cSrcweir 				{
2765cdf0e10cSrcweir 					if(!rCandidate.isClosed() && nIndex + 1 == nPointCount)
2766cdf0e10cSrcweir 					{
2767cdf0e10cSrcweir 						// do not create next vector for end point of open polygon
2768cdf0e10cSrcweir 					}
2769cdf0e10cSrcweir 					else
2770cdf0e10cSrcweir 					{
2771cdf0e10cSrcweir 						const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
2772cdf0e10cSrcweir 						rCandidate.setNextControlPoint(nIndex, interpolate(rCandidate.getB2DPoint(nIndex), rCandidate.getB2DPoint(nNextIndex), 1.0 / 3.0));
2773cdf0e10cSrcweir 						bRetval = true;
2774cdf0e10cSrcweir 					}
2775cdf0e10cSrcweir 				}
2776cdf0e10cSrcweir 			}
2777cdf0e10cSrcweir 
2778cdf0e10cSrcweir 			return bRetval;
2779cdf0e10cSrcweir 		}
2780cdf0e10cSrcweir 
setContinuity(const B2DPolygon & rCandidate,B2VectorContinuity eContinuity)2781cdf0e10cSrcweir 		B2DPolygon setContinuity(const B2DPolygon& rCandidate, B2VectorContinuity eContinuity)
2782cdf0e10cSrcweir 		{
2783cdf0e10cSrcweir 			B2DPolygon aRetval(rCandidate);
2784cdf0e10cSrcweir 
2785cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
2786cdf0e10cSrcweir 			{
2787cdf0e10cSrcweir 				setContinuityInPoint(aRetval, a, eContinuity);
2788cdf0e10cSrcweir 			}
2789cdf0e10cSrcweir 
2790cdf0e10cSrcweir 			return aRetval;
2791cdf0e10cSrcweir 		}
2792cdf0e10cSrcweir 
setContinuityInPoint(B2DPolygon & rCandidate,sal_uInt32 nIndex,B2VectorContinuity eContinuity)2793cdf0e10cSrcweir 		bool setContinuityInPoint(B2DPolygon& rCandidate, sal_uInt32 nIndex, B2VectorContinuity eContinuity)
2794cdf0e10cSrcweir 		{
2795cdf0e10cSrcweir 			OSL_ENSURE(nIndex < rCandidate.count(), "setContinuityInPoint: Access to polygon out of range (!)");
2796cdf0e10cSrcweir 			bool bRetval(false);
2797cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
2798cdf0e10cSrcweir 
2799cdf0e10cSrcweir 			if(nPointCount)
2800cdf0e10cSrcweir 			{
2801cdf0e10cSrcweir 				const B2DPoint aCurrentPoint(rCandidate.getB2DPoint(nIndex));
2802cdf0e10cSrcweir 
2803cdf0e10cSrcweir 				switch(eContinuity)
2804cdf0e10cSrcweir 				{
2805cdf0e10cSrcweir 					case CONTINUITY_NONE :
2806cdf0e10cSrcweir 					{
2807cdf0e10cSrcweir 						if(rCandidate.isPrevControlPointUsed(nIndex))
2808cdf0e10cSrcweir 						{
2809cdf0e10cSrcweir 							if(!rCandidate.isClosed() && 0 == nIndex)
2810cdf0e10cSrcweir 							{
2811cdf0e10cSrcweir 								// remove existing previous vector for start point of open polygon
2812cdf0e10cSrcweir 								rCandidate.resetPrevControlPoint(nIndex);
2813cdf0e10cSrcweir 							}
2814cdf0e10cSrcweir 							else
2815cdf0e10cSrcweir 							{
2816cdf0e10cSrcweir 								const sal_uInt32 nPrevIndex((nIndex + (nPointCount - 1)) % nPointCount);
2817cdf0e10cSrcweir 								rCandidate.setPrevControlPoint(nIndex, interpolate(aCurrentPoint, rCandidate.getB2DPoint(nPrevIndex), 1.0 / 3.0));
2818cdf0e10cSrcweir 							}
2819cdf0e10cSrcweir 
2820cdf0e10cSrcweir 							bRetval = true;
2821cdf0e10cSrcweir 						}
2822cdf0e10cSrcweir 
2823cdf0e10cSrcweir 						if(rCandidate.isNextControlPointUsed(nIndex))
2824cdf0e10cSrcweir 						{
2825cdf0e10cSrcweir 							if(!rCandidate.isClosed() && nIndex == nPointCount + 1)
2826cdf0e10cSrcweir 							{
2827cdf0e10cSrcweir 								// remove next vector for end point of open polygon
2828cdf0e10cSrcweir 								rCandidate.resetNextControlPoint(nIndex);
2829cdf0e10cSrcweir 							}
2830cdf0e10cSrcweir 							else
2831cdf0e10cSrcweir 							{
2832cdf0e10cSrcweir 								const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
2833cdf0e10cSrcweir 								rCandidate.setNextControlPoint(nIndex, interpolate(aCurrentPoint, rCandidate.getB2DPoint(nNextIndex), 1.0 / 3.0));
2834cdf0e10cSrcweir 							}
2835cdf0e10cSrcweir 
2836cdf0e10cSrcweir 							bRetval = true;
2837cdf0e10cSrcweir 						}
2838cdf0e10cSrcweir 
2839cdf0e10cSrcweir 						break;
2840cdf0e10cSrcweir 					}
2841cdf0e10cSrcweir 					case CONTINUITY_C1 :
2842cdf0e10cSrcweir 					{
2843cdf0e10cSrcweir 						if(rCandidate.isPrevControlPointUsed(nIndex) && rCandidate.isNextControlPointUsed(nIndex))
2844cdf0e10cSrcweir 						{
2845cdf0e10cSrcweir 							// lengths both exist since both are used
2846cdf0e10cSrcweir 							B2DVector aVectorPrev(rCandidate.getPrevControlPoint(nIndex) - aCurrentPoint);
2847cdf0e10cSrcweir 							B2DVector aVectorNext(rCandidate.getNextControlPoint(nIndex) - aCurrentPoint);
2848cdf0e10cSrcweir 							const double fLenPrev(aVectorPrev.getLength());
2849cdf0e10cSrcweir 							const double fLenNext(aVectorNext.getLength());
2850cdf0e10cSrcweir 							aVectorPrev.normalize();
2851cdf0e10cSrcweir 							aVectorNext.normalize();
2852cdf0e10cSrcweir 							const B2VectorOrientation aOrientation(getOrientation(aVectorPrev, aVectorNext));
2853cdf0e10cSrcweir 
2854cdf0e10cSrcweir 							if(ORIENTATION_NEUTRAL == aOrientation && aVectorPrev.scalar(aVectorNext) < 0.0)
2855cdf0e10cSrcweir 							{
2856cdf0e10cSrcweir 								// parallel and opposite direction; check length
2857cdf0e10cSrcweir 								if(fTools::equal(fLenPrev, fLenNext))
2858cdf0e10cSrcweir 								{
2859cdf0e10cSrcweir 									// this would be even C2, but we want C1. Use the lengths of the corresponding edges.
2860cdf0e10cSrcweir 									const sal_uInt32 nPrevIndex((nIndex + (nPointCount - 1)) % nPointCount);
2861cdf0e10cSrcweir 									const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
2862cdf0e10cSrcweir 									const double fLenPrevEdge(B2DVector(rCandidate.getB2DPoint(nPrevIndex) - aCurrentPoint).getLength() * (1.0 / 3.0));
2863cdf0e10cSrcweir 									const double fLenNextEdge(B2DVector(rCandidate.getB2DPoint(nNextIndex) - aCurrentPoint).getLength() * (1.0 / 3.0));
2864cdf0e10cSrcweir 
2865cdf0e10cSrcweir 									rCandidate.setControlPoints(nIndex,
2866cdf0e10cSrcweir 										aCurrentPoint + (aVectorPrev * fLenPrevEdge),
2867cdf0e10cSrcweir 										aCurrentPoint + (aVectorNext * fLenNextEdge));
2868cdf0e10cSrcweir 									bRetval = true;
2869cdf0e10cSrcweir 								}
2870cdf0e10cSrcweir 							}
2871cdf0e10cSrcweir 							else
2872cdf0e10cSrcweir 							{
2873cdf0e10cSrcweir 								// not parallel or same direction, set vectors and length
2874cdf0e10cSrcweir 								const B2DVector aNormalizedPerpendicular(getNormalizedPerpendicular(aVectorPrev + aVectorNext));
2875cdf0e10cSrcweir 
2876cdf0e10cSrcweir 								if(ORIENTATION_POSITIVE == aOrientation)
2877cdf0e10cSrcweir 								{
2878cdf0e10cSrcweir 									rCandidate.setControlPoints(nIndex,
2879cdf0e10cSrcweir 										aCurrentPoint - (aNormalizedPerpendicular * fLenPrev),
2880cdf0e10cSrcweir 										aCurrentPoint + (aNormalizedPerpendicular * fLenNext));
2881cdf0e10cSrcweir 								}
2882cdf0e10cSrcweir 								else
2883cdf0e10cSrcweir 								{
2884cdf0e10cSrcweir 									rCandidate.setControlPoints(nIndex,
2885cdf0e10cSrcweir 										aCurrentPoint + (aNormalizedPerpendicular * fLenPrev),
2886cdf0e10cSrcweir 										aCurrentPoint - (aNormalizedPerpendicular * fLenNext));
2887cdf0e10cSrcweir 								}
2888cdf0e10cSrcweir 
2889cdf0e10cSrcweir 								bRetval = true;
2890cdf0e10cSrcweir 							}
2891cdf0e10cSrcweir 						}
2892cdf0e10cSrcweir 						break;
2893cdf0e10cSrcweir 					}
2894cdf0e10cSrcweir 					case CONTINUITY_C2 :
2895cdf0e10cSrcweir 					{
2896cdf0e10cSrcweir 						if(rCandidate.isPrevControlPointUsed(nIndex) && rCandidate.isNextControlPointUsed(nIndex))
2897cdf0e10cSrcweir 						{
2898cdf0e10cSrcweir 							// lengths both exist since both are used
2899cdf0e10cSrcweir 							B2DVector aVectorPrev(rCandidate.getPrevControlPoint(nIndex) - aCurrentPoint);
2900cdf0e10cSrcweir 							B2DVector aVectorNext(rCandidate.getNextControlPoint(nIndex) - aCurrentPoint);
2901cdf0e10cSrcweir 							const double fCommonLength((aVectorPrev.getLength() + aVectorNext.getLength()) / 2.0);
2902cdf0e10cSrcweir 							aVectorPrev.normalize();
2903cdf0e10cSrcweir 							aVectorNext.normalize();
2904cdf0e10cSrcweir 							const B2VectorOrientation aOrientation(getOrientation(aVectorPrev, aVectorNext));
2905cdf0e10cSrcweir 
2906cdf0e10cSrcweir 							if(ORIENTATION_NEUTRAL == aOrientation && aVectorPrev.scalar(aVectorNext) < 0.0)
2907cdf0e10cSrcweir 							{
2908cdf0e10cSrcweir 								// parallel and opposite direction; set length. Use one direction for better numerical correctness
2909cdf0e10cSrcweir 								const B2DVector aScaledDirection(aVectorPrev * fCommonLength);
2910cdf0e10cSrcweir 
2911cdf0e10cSrcweir 								rCandidate.setControlPoints(nIndex,
2912cdf0e10cSrcweir 									aCurrentPoint + aScaledDirection,
2913cdf0e10cSrcweir 									aCurrentPoint - aScaledDirection);
2914cdf0e10cSrcweir 							}
2915cdf0e10cSrcweir 							else
2916cdf0e10cSrcweir 							{
2917cdf0e10cSrcweir 								// not parallel or same direction, set vectors and length
2918cdf0e10cSrcweir 								const B2DVector aNormalizedPerpendicular(getNormalizedPerpendicular(aVectorPrev + aVectorNext));
2919cdf0e10cSrcweir 								const B2DVector aPerpendicular(aNormalizedPerpendicular * fCommonLength);
2920cdf0e10cSrcweir 
2921cdf0e10cSrcweir 								if(ORIENTATION_POSITIVE == aOrientation)
2922cdf0e10cSrcweir 								{
2923cdf0e10cSrcweir 									rCandidate.setControlPoints(nIndex,
2924cdf0e10cSrcweir 										aCurrentPoint - aPerpendicular,
2925cdf0e10cSrcweir 										aCurrentPoint + aPerpendicular);
2926cdf0e10cSrcweir 								}
2927cdf0e10cSrcweir 								else
2928cdf0e10cSrcweir 								{
2929cdf0e10cSrcweir 									rCandidate.setControlPoints(nIndex,
2930cdf0e10cSrcweir 										aCurrentPoint + aPerpendicular,
2931cdf0e10cSrcweir 										aCurrentPoint - aPerpendicular);
2932cdf0e10cSrcweir 								}
2933cdf0e10cSrcweir 							}
2934cdf0e10cSrcweir 
2935cdf0e10cSrcweir 							bRetval = true;
2936cdf0e10cSrcweir 						}
2937cdf0e10cSrcweir 						break;
2938cdf0e10cSrcweir 					}
2939cdf0e10cSrcweir 				}
2940cdf0e10cSrcweir 			}
2941cdf0e10cSrcweir 
2942cdf0e10cSrcweir 			return bRetval;
2943cdf0e10cSrcweir 		}
2944cdf0e10cSrcweir 
growInNormalDirection(const B2DPolygon & rCandidate,double fValue)2945cdf0e10cSrcweir 		B2DPolygon growInNormalDirection(const B2DPolygon& rCandidate, double fValue)
2946cdf0e10cSrcweir 		{
2947cdf0e10cSrcweir 			if(0.0 != fValue)
2948cdf0e10cSrcweir 			{
2949cdf0e10cSrcweir 				if(rCandidate.areControlPointsUsed())
2950cdf0e10cSrcweir 				{
2951cdf0e10cSrcweir 					// call myself recursively with subdivided input
2952cdf0e10cSrcweir 					const B2DPolygon aCandidate(adaptiveSubdivideByAngle(rCandidate));
2953cdf0e10cSrcweir 					return growInNormalDirection(aCandidate, fValue);
2954cdf0e10cSrcweir 				}
2955cdf0e10cSrcweir 				else
2956cdf0e10cSrcweir 				{
2957cdf0e10cSrcweir 					B2DPolygon aRetval;
2958cdf0e10cSrcweir 					const sal_uInt32 nPointCount(rCandidate.count());
2959cdf0e10cSrcweir 
2960cdf0e10cSrcweir 					if(nPointCount)
2961cdf0e10cSrcweir 					{
2962cdf0e10cSrcweir 						B2DPoint aPrev(rCandidate.getB2DPoint(nPointCount - 1L));
2963cdf0e10cSrcweir 						B2DPoint aCurrent(rCandidate.getB2DPoint(0L));
2964cdf0e10cSrcweir 
2965cdf0e10cSrcweir 						for(sal_uInt32 a(0L); a < nPointCount; a++)
2966cdf0e10cSrcweir 						{
2967cdf0e10cSrcweir 							const B2DPoint aNext(rCandidate.getB2DPoint(a + 1L == nPointCount ? 0L : a + 1L));
2968cdf0e10cSrcweir 							const B2DVector aBack(aPrev - aCurrent);
2969cdf0e10cSrcweir 							const B2DVector aForw(aNext - aCurrent);
2970cdf0e10cSrcweir 							const B2DVector aPerpBack(getNormalizedPerpendicular(aBack));
2971cdf0e10cSrcweir 							const B2DVector aPerpForw(getNormalizedPerpendicular(aForw));
2972cdf0e10cSrcweir 							B2DVector aDirection(aPerpBack - aPerpForw);
2973cdf0e10cSrcweir 							aDirection.normalize();
2974cdf0e10cSrcweir 							aDirection *= fValue;
2975cdf0e10cSrcweir 							aRetval.append(aCurrent + aDirection);
2976cdf0e10cSrcweir 
2977cdf0e10cSrcweir 							// prepare next step
2978cdf0e10cSrcweir 							aPrev = aCurrent;
2979cdf0e10cSrcweir 							aCurrent = aNext;
2980cdf0e10cSrcweir 						}
2981cdf0e10cSrcweir 					}
2982cdf0e10cSrcweir 
2983cdf0e10cSrcweir 					// copy closed state
2984cdf0e10cSrcweir 					aRetval.setClosed(rCandidate.isClosed());
2985cdf0e10cSrcweir 
2986cdf0e10cSrcweir 					return aRetval;
2987cdf0e10cSrcweir 				}
2988cdf0e10cSrcweir 			}
2989cdf0e10cSrcweir 			else
2990cdf0e10cSrcweir 			{
2991cdf0e10cSrcweir 				return rCandidate;
2992cdf0e10cSrcweir 			}
2993cdf0e10cSrcweir 		}
2994cdf0e10cSrcweir 
reSegmentPolygon(const B2DPolygon & rCandidate,sal_uInt32 nSegments)2995cdf0e10cSrcweir 		B2DPolygon reSegmentPolygon(const B2DPolygon& rCandidate, sal_uInt32 nSegments)
2996cdf0e10cSrcweir 		{
2997cdf0e10cSrcweir 			B2DPolygon aRetval;
2998cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
2999cdf0e10cSrcweir 
3000cdf0e10cSrcweir 			if(nPointCount && nSegments)
3001cdf0e10cSrcweir 			{
3002cdf0e10cSrcweir 				// get current segment count
3003cdf0e10cSrcweir 				const sal_uInt32 nSegmentCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
3004cdf0e10cSrcweir 
3005cdf0e10cSrcweir 				if(nSegmentCount == nSegments)
3006cdf0e10cSrcweir 				{
3007cdf0e10cSrcweir 					aRetval = rCandidate;
3008cdf0e10cSrcweir 				}
3009cdf0e10cSrcweir 				else
3010cdf0e10cSrcweir 				{
3011cdf0e10cSrcweir 					const double fLength(getLength(rCandidate));
3012cdf0e10cSrcweir 					const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nSegments : nSegments + 1L);
3013cdf0e10cSrcweir 
3014cdf0e10cSrcweir 					for(sal_uInt32 a(0L); a < nLoopCount; a++)
3015cdf0e10cSrcweir 					{
3016cdf0e10cSrcweir 						const double fRelativePos((double)a / (double)nSegments); // 0.0 .. 1.0
3017cdf0e10cSrcweir 						const B2DPoint aNewPoint(getPositionRelative(rCandidate, fRelativePos, fLength));
3018cdf0e10cSrcweir 						aRetval.append(aNewPoint);
3019cdf0e10cSrcweir 					}
3020cdf0e10cSrcweir 
3021cdf0e10cSrcweir 					// copy closed flag
3022cdf0e10cSrcweir 					aRetval.setClosed(rCandidate.isClosed());
3023cdf0e10cSrcweir 				}
3024cdf0e10cSrcweir 			}
3025cdf0e10cSrcweir 
3026cdf0e10cSrcweir 			return aRetval;
3027cdf0e10cSrcweir 		}
3028cdf0e10cSrcweir 
reSegmentPolygonEdges(const B2DPolygon & rCandidate,sal_uInt32 nSubEdges,bool bHandleCurvedEdges,bool bHandleStraightEdges)3029cdf0e10cSrcweir 		B2DPolygon reSegmentPolygonEdges(const B2DPolygon& rCandidate, sal_uInt32 nSubEdges, bool bHandleCurvedEdges, bool bHandleStraightEdges)
3030cdf0e10cSrcweir 		{
3031cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
3032cdf0e10cSrcweir 
3033cdf0e10cSrcweir             if(nPointCount < 2 || nSubEdges < 2 || (!bHandleCurvedEdges && !bHandleStraightEdges))
3034cdf0e10cSrcweir             {
3035cdf0e10cSrcweir                 // nothing to do:
3036cdf0e10cSrcweir                 // - less than two points -> no edge at all
3037cdf0e10cSrcweir                 // - less than two nSubEdges -> no resegment necessary
3038cdf0e10cSrcweir                 // - neither bHandleCurvedEdges nor bHandleStraightEdges -> nothing to do
3039cdf0e10cSrcweir                 return rCandidate;
3040cdf0e10cSrcweir             }
3041cdf0e10cSrcweir             else
3042cdf0e10cSrcweir             {
3043cdf0e10cSrcweir     			B2DPolygon aRetval;
3044cdf0e10cSrcweir                 const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
3045cdf0e10cSrcweir                 B2DCubicBezier aCurrentEdge;
3046cdf0e10cSrcweir 
3047cdf0e10cSrcweir                 // prepare first edge and add start point to target
3048cdf0e10cSrcweir                 aCurrentEdge.setStartPoint(rCandidate.getB2DPoint(0));
3049cdf0e10cSrcweir                 aRetval.append(aCurrentEdge.getStartPoint());
3050cdf0e10cSrcweir 
3051cdf0e10cSrcweir                 for(sal_uInt32 a(0); a < nEdgeCount; a++)
3052cdf0e10cSrcweir                 {
3053cdf0e10cSrcweir                     // fill edge
3054cdf0e10cSrcweir                     const sal_uInt32 nNextIndex((a + 1) % nPointCount);
3055cdf0e10cSrcweir                     aCurrentEdge.setControlPointA(rCandidate.getNextControlPoint(a));
3056cdf0e10cSrcweir                     aCurrentEdge.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
3057cdf0e10cSrcweir                     aCurrentEdge.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
3058cdf0e10cSrcweir 
3059cdf0e10cSrcweir                     if(aCurrentEdge.isBezier())
3060cdf0e10cSrcweir                     {
3061cdf0e10cSrcweir                         if(bHandleCurvedEdges)
3062cdf0e10cSrcweir                         {
3063cdf0e10cSrcweir                             for(sal_uInt32 b(nSubEdges); b > 1; b--)
3064cdf0e10cSrcweir                             {
3065cdf0e10cSrcweir                                 const double fSplitPoint(1.0 / b);
3066cdf0e10cSrcweir                                 B2DCubicBezier aLeftPart;
3067cdf0e10cSrcweir 
3068cdf0e10cSrcweir                                 aCurrentEdge.split(fSplitPoint, &aLeftPart, &aCurrentEdge);
3069cdf0e10cSrcweir                                 aRetval.appendBezierSegment(aLeftPart.getControlPointA(), aLeftPart.getControlPointB(), aLeftPart.getEndPoint());
3070cdf0e10cSrcweir                             }
3071cdf0e10cSrcweir                         }
3072cdf0e10cSrcweir 
3073cdf0e10cSrcweir                         // copy remaining segment to target
3074cdf0e10cSrcweir                         aRetval.appendBezierSegment(aCurrentEdge.getControlPointA(), aCurrentEdge.getControlPointB(), aCurrentEdge.getEndPoint());
3075cdf0e10cSrcweir                     }
3076cdf0e10cSrcweir                     else
3077cdf0e10cSrcweir                     {
3078cdf0e10cSrcweir                         if(bHandleStraightEdges)
3079cdf0e10cSrcweir                         {
3080cdf0e10cSrcweir                             for(sal_uInt32 b(nSubEdges); b > 1; b--)
3081cdf0e10cSrcweir                             {
3082cdf0e10cSrcweir                                 const double fSplitPoint(1.0 / b);
3083cdf0e10cSrcweir                                 const B2DPoint aSplitPoint(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fSplitPoint));
3084cdf0e10cSrcweir 
3085cdf0e10cSrcweir                                 aRetval.append(aSplitPoint);
3086cdf0e10cSrcweir                                 aCurrentEdge.setStartPoint(aSplitPoint);
3087cdf0e10cSrcweir                             }
3088cdf0e10cSrcweir                         }
3089cdf0e10cSrcweir 
3090cdf0e10cSrcweir                         // copy remaining segment to target
3091cdf0e10cSrcweir                         aRetval.append(aCurrentEdge.getEndPoint());
3092cdf0e10cSrcweir                     }
3093cdf0e10cSrcweir 
3094cdf0e10cSrcweir                     // prepare next step
3095cdf0e10cSrcweir                     aCurrentEdge.setStartPoint(aCurrentEdge.getEndPoint());
3096cdf0e10cSrcweir                 }
3097cdf0e10cSrcweir 
3098cdf0e10cSrcweir                 // copy closed flag and return
3099cdf0e10cSrcweir                 aRetval.setClosed(rCandidate.isClosed());
3100cdf0e10cSrcweir                 return aRetval;
3101cdf0e10cSrcweir             }
3102cdf0e10cSrcweir         }
3103cdf0e10cSrcweir 
interpolate(const B2DPolygon & rOld1,const B2DPolygon & rOld2,double t)3104cdf0e10cSrcweir 		B2DPolygon interpolate(const B2DPolygon& rOld1, const B2DPolygon& rOld2, double t)
3105cdf0e10cSrcweir 		{
3106cdf0e10cSrcweir 			OSL_ENSURE(rOld1.count() == rOld2.count(), "B2DPolygon interpolate: Different geometry (!)");
3107cdf0e10cSrcweir 
3108cdf0e10cSrcweir 			if(fTools::lessOrEqual(t, 0.0) || rOld1 == rOld2)
3109cdf0e10cSrcweir 			{
3110cdf0e10cSrcweir 				return rOld1;
3111cdf0e10cSrcweir 			}
3112cdf0e10cSrcweir 			else if(fTools::moreOrEqual(t, 1.0))
3113cdf0e10cSrcweir 			{
3114cdf0e10cSrcweir 				return rOld2;
3115cdf0e10cSrcweir 			}
3116cdf0e10cSrcweir 			else
3117cdf0e10cSrcweir 			{
3118cdf0e10cSrcweir 				B2DPolygon aRetval;
3119cdf0e10cSrcweir 				const bool bInterpolateVectors(rOld1.areControlPointsUsed() || rOld2.areControlPointsUsed());
3120cdf0e10cSrcweir 				aRetval.setClosed(rOld1.isClosed() && rOld2.isClosed());
3121cdf0e10cSrcweir 
3122cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < rOld1.count(); a++)
3123cdf0e10cSrcweir 				{
3124cdf0e10cSrcweir 					aRetval.append(interpolate(rOld1.getB2DPoint(a), rOld2.getB2DPoint(a), t));
3125cdf0e10cSrcweir 
3126cdf0e10cSrcweir 					if(bInterpolateVectors)
3127cdf0e10cSrcweir 					{
3128cdf0e10cSrcweir 						aRetval.setPrevControlPoint(a, interpolate(rOld1.getPrevControlPoint(a), rOld2.getPrevControlPoint(a), t));
3129cdf0e10cSrcweir 						aRetval.setNextControlPoint(a, interpolate(rOld1.getNextControlPoint(a), rOld2.getNextControlPoint(a), t));
3130cdf0e10cSrcweir 					}
3131cdf0e10cSrcweir 				}
3132cdf0e10cSrcweir 
3133cdf0e10cSrcweir 				return aRetval;
3134cdf0e10cSrcweir 			}
3135cdf0e10cSrcweir 		}
3136cdf0e10cSrcweir 
isPolyPolygonEqualRectangle(const B2DPolyPolygon & rPolyPoly,const B2DRange & rRect)3137cdf0e10cSrcweir 		bool isPolyPolygonEqualRectangle( const B2DPolyPolygon& rPolyPoly,
3138cdf0e10cSrcweir 										  const B2DRange&	   rRect )
3139cdf0e10cSrcweir         {
3140cdf0e10cSrcweir             // exclude some cheap cases first
3141cdf0e10cSrcweir             if( rPolyPoly.count() != 1 )
3142cdf0e10cSrcweir                 return false;
3143cdf0e10cSrcweir 
3144cdf0e10cSrcweir             // fill array with rectangle vertices
3145cdf0e10cSrcweir             const B2DPoint aPoints[] =
3146cdf0e10cSrcweir               {
3147cdf0e10cSrcweir 				  B2DPoint(rRect.getMinX(),rRect.getMinY()),
3148cdf0e10cSrcweir 				  B2DPoint(rRect.getMaxX(),rRect.getMinY()),
3149cdf0e10cSrcweir 				  B2DPoint(rRect.getMaxX(),rRect.getMaxY()),
3150cdf0e10cSrcweir 				  B2DPoint(rRect.getMinX(),rRect.getMaxY())
3151cdf0e10cSrcweir               };
3152cdf0e10cSrcweir 
3153cdf0e10cSrcweir 			const B2DPolygon& rPoly( rPolyPoly.getB2DPolygon(0) );
3154cdf0e10cSrcweir 			const sal_uInt32 nCount( rPoly.count() );
3155cdf0e10cSrcweir 			const double epsilon = ::std::numeric_limits<double>::epsilon();
3156cdf0e10cSrcweir 
3157cdf0e10cSrcweir 			for(unsigned int j=0; j<4; ++j)
3158cdf0e10cSrcweir 			{
3159cdf0e10cSrcweir 				const B2DPoint &p1 = aPoints[j];
3160cdf0e10cSrcweir 				const B2DPoint &p2 = aPoints[(j+1)%4];
3161cdf0e10cSrcweir 				bool bPointOnBoundary = false;
3162cdf0e10cSrcweir 				for( sal_uInt32 i=0; i<nCount; ++i )
3163cdf0e10cSrcweir 				{
3164cdf0e10cSrcweir 					const B2DPoint p(rPoly.getB2DPoint(i));
3165cdf0e10cSrcweir 
3166cdf0e10cSrcweir 					//	   1 | x0 y0 1 |
3167cdf0e10cSrcweir 					// A = - | x1 y1 1 |
3168cdf0e10cSrcweir 					//	   2 | x2 y2 1 |
3169cdf0e10cSrcweir 					double fDoubleArea = p2.getX()*p.getY() -
3170cdf0e10cSrcweir 										 p2.getY()*p.getX() -
3171cdf0e10cSrcweir 										 p1.getX()*p.getY() +
3172cdf0e10cSrcweir 										 p1.getY()*p.getX() +
3173cdf0e10cSrcweir 										 p1.getX()*p2.getY() -
3174cdf0e10cSrcweir 										 p1.getY()*p2.getX();
3175cdf0e10cSrcweir 
3176cdf0e10cSrcweir 					if(fDoubleArea < epsilon)
3177cdf0e10cSrcweir 					{
3178cdf0e10cSrcweir 						bPointOnBoundary=true;
3179cdf0e10cSrcweir 						break;
3180cdf0e10cSrcweir 					}
3181cdf0e10cSrcweir 				}
3182cdf0e10cSrcweir 				if(!(bPointOnBoundary))
3183cdf0e10cSrcweir 					return false;
3184cdf0e10cSrcweir 			}
3185cdf0e10cSrcweir 
3186cdf0e10cSrcweir 			return true;
3187cdf0e10cSrcweir         }
3188cdf0e10cSrcweir 
3189cdf0e10cSrcweir 
3190cdf0e10cSrcweir 		// create simplified version of the original polygon by
3191cdf0e10cSrcweir 		// replacing segments with spikes/loops and self intersections
3192cdf0e10cSrcweir 		// by several trivial sub-segments
createSimplifiedPolygon(const B2DPolygon & rCandidate)3193cdf0e10cSrcweir 		B2DPolygon createSimplifiedPolygon( const B2DPolygon& rCandidate )
3194cdf0e10cSrcweir 		{
3195cdf0e10cSrcweir 			const sal_uInt32 nCount(rCandidate.count());
3196cdf0e10cSrcweir 
3197cdf0e10cSrcweir 			if(nCount && rCandidate.areControlPointsUsed())
3198cdf0e10cSrcweir 			{
3199cdf0e10cSrcweir 				const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nCount : nCount - 1);
3200cdf0e10cSrcweir 				B2DPolygon aRetval;
3201cdf0e10cSrcweir 				B2DCubicBezier aSegment;
3202cdf0e10cSrcweir 
3203cdf0e10cSrcweir 				aSegment.setStartPoint(rCandidate.getB2DPoint(0));
3204cdf0e10cSrcweir 				aRetval.append(aSegment.getStartPoint());
3205cdf0e10cSrcweir 
3206cdf0e10cSrcweir 				for(sal_uInt32 a(0); a < nEdgeCount; a++)
3207cdf0e10cSrcweir 				{
3208cdf0e10cSrcweir 					// fill edge
3209cdf0e10cSrcweir 					const sal_uInt32 nNextIndex((a + 1) % nCount);
3210cdf0e10cSrcweir 					aSegment.setControlPointA(rCandidate.getNextControlPoint(a));
3211cdf0e10cSrcweir 					aSegment.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
3212cdf0e10cSrcweir 					aSegment.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
3213cdf0e10cSrcweir 
3214cdf0e10cSrcweir 					if(aSegment.isBezier())
3215cdf0e10cSrcweir 					{
3216cdf0e10cSrcweir 						double fExtremumPos(0.0);
3217cdf0e10cSrcweir 						sal_uInt32 nExtremumCounter(4);
3218cdf0e10cSrcweir 
3219cdf0e10cSrcweir 						while(nExtremumCounter-- && aSegment.isBezier() && aSegment.getMinimumExtremumPosition(fExtremumPos))
3220cdf0e10cSrcweir 						{
3221cdf0e10cSrcweir 							// split off left, now extremum-free part and append
3222cdf0e10cSrcweir 							B2DCubicBezier aLeft;
3223cdf0e10cSrcweir 
3224cdf0e10cSrcweir 							aSegment.split(fExtremumPos, &aLeft, &aSegment);
3225cdf0e10cSrcweir 		                    aLeft.testAndSolveTrivialBezier();
3226cdf0e10cSrcweir 		                    aSegment.testAndSolveTrivialBezier();
3227cdf0e10cSrcweir 
3228cdf0e10cSrcweir 							if(aLeft.isBezier())
3229cdf0e10cSrcweir 							{
3230cdf0e10cSrcweir 								aRetval.appendBezierSegment(aLeft.getControlPointA(), aLeft.getControlPointB(), aLeft.getEndPoint());
3231cdf0e10cSrcweir 							}
3232cdf0e10cSrcweir 							else
3233cdf0e10cSrcweir 							{
3234cdf0e10cSrcweir 								aRetval.append(aLeft.getEndPoint());
3235cdf0e10cSrcweir 							}
3236cdf0e10cSrcweir 						}
3237cdf0e10cSrcweir 
3238cdf0e10cSrcweir 						// append (evtl. reduced) rest of Segment
3239cdf0e10cSrcweir 						if(aSegment.isBezier())
3240cdf0e10cSrcweir 						{
3241cdf0e10cSrcweir 							aRetval.appendBezierSegment(aSegment.getControlPointA(), aSegment.getControlPointB(), aSegment.getEndPoint());
3242cdf0e10cSrcweir 						}
3243cdf0e10cSrcweir 						else
3244cdf0e10cSrcweir 						{
3245cdf0e10cSrcweir 							aRetval.append(aSegment.getEndPoint());
3246cdf0e10cSrcweir 						}
3247cdf0e10cSrcweir 					}
3248cdf0e10cSrcweir 					else
3249cdf0e10cSrcweir 					{
3250cdf0e10cSrcweir 						// simple edge, append end point
3251cdf0e10cSrcweir 						aRetval.append(aSegment.getEndPoint());
3252cdf0e10cSrcweir 					}
3253cdf0e10cSrcweir 
3254cdf0e10cSrcweir 					// prepare next edge
3255cdf0e10cSrcweir 					aSegment.setStartPoint(aSegment.getEndPoint());
3256cdf0e10cSrcweir 				}
3257cdf0e10cSrcweir 
3258cdf0e10cSrcweir 				// copy closed flag and check for double points
3259cdf0e10cSrcweir 				aRetval.setClosed(rCandidate.isClosed());
3260cdf0e10cSrcweir 				aRetval.removeDoublePoints();
3261cdf0e10cSrcweir 
3262cdf0e10cSrcweir 				return aRetval;
3263cdf0e10cSrcweir 			}
3264cdf0e10cSrcweir 			else
3265cdf0e10cSrcweir 			{
3266cdf0e10cSrcweir 				return rCandidate;
3267cdf0e10cSrcweir 			}
3268cdf0e10cSrcweir 		}
3269cdf0e10cSrcweir 
3270cdf0e10cSrcweir 		// #i76891#
simplifyCurveSegments(const B2DPolygon & rCandidate)3271cdf0e10cSrcweir 		B2DPolygon simplifyCurveSegments(const B2DPolygon& rCandidate)
3272cdf0e10cSrcweir 		{
3273cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
3274cdf0e10cSrcweir 
3275cdf0e10cSrcweir 			if(nPointCount && rCandidate.areControlPointsUsed())
3276cdf0e10cSrcweir 			{
3277cdf0e10cSrcweir 				// prepare loop
3278cdf0e10cSrcweir 				const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
3279cdf0e10cSrcweir 				B2DPolygon aRetval;
3280cdf0e10cSrcweir 				B2DCubicBezier aBezier;
3281cdf0e10cSrcweir 				aBezier.setStartPoint(rCandidate.getB2DPoint(0));
3282cdf0e10cSrcweir 
3283cdf0e10cSrcweir 				// try to avoid costly reallocations
3284cdf0e10cSrcweir 				aRetval.reserve( nEdgeCount+1);
3285cdf0e10cSrcweir 
3286cdf0e10cSrcweir 				// add start point
3287cdf0e10cSrcweir 				aRetval.append(aBezier.getStartPoint());
3288cdf0e10cSrcweir 
3289cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nEdgeCount; a++)
3290cdf0e10cSrcweir 				{
3291cdf0e10cSrcweir 					// get values for edge
3292cdf0e10cSrcweir 					const sal_uInt32 nNextIndex((a + 1) % nPointCount);
3293cdf0e10cSrcweir 					aBezier.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
3294cdf0e10cSrcweir 					aBezier.setControlPointA(rCandidate.getNextControlPoint(a));
3295cdf0e10cSrcweir 					aBezier.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
3296cdf0e10cSrcweir 					aBezier.testAndSolveTrivialBezier();
3297cdf0e10cSrcweir 
3298cdf0e10cSrcweir 					// still bezier?
3299cdf0e10cSrcweir 					if(aBezier.isBezier())
3300cdf0e10cSrcweir 					{
3301cdf0e10cSrcweir 						// add edge with control vectors
3302cdf0e10cSrcweir 						aRetval.appendBezierSegment(aBezier.getControlPointA(), aBezier.getControlPointB(), aBezier.getEndPoint());
3303cdf0e10cSrcweir 					}
3304cdf0e10cSrcweir 					else
3305cdf0e10cSrcweir 					{
3306cdf0e10cSrcweir 						// add edge
3307cdf0e10cSrcweir 						aRetval.append(aBezier.getEndPoint());
3308cdf0e10cSrcweir 					}
3309cdf0e10cSrcweir 
3310cdf0e10cSrcweir 					// next point
3311cdf0e10cSrcweir 					aBezier.setStartPoint(aBezier.getEndPoint());
3312cdf0e10cSrcweir 				}
3313cdf0e10cSrcweir 
3314cdf0e10cSrcweir 				if(rCandidate.isClosed())
3315cdf0e10cSrcweir 				{
3316cdf0e10cSrcweir 					// set closed flag, rescue control point and correct last double point
3317cdf0e10cSrcweir 					closeWithGeometryChange(aRetval);
3318cdf0e10cSrcweir 				}
3319cdf0e10cSrcweir 
3320cdf0e10cSrcweir 				return aRetval;
3321cdf0e10cSrcweir 			}
3322cdf0e10cSrcweir 			else
3323cdf0e10cSrcweir 			{
3324cdf0e10cSrcweir 				return rCandidate;
3325cdf0e10cSrcweir 			}
3326cdf0e10cSrcweir 		}
3327cdf0e10cSrcweir 
3328cdf0e10cSrcweir 		// makes the given indexed point the new polygon start point. To do that, the points in the
3329cdf0e10cSrcweir 		// polygon will be rotated. This is only valid for closed polygons, for non-closed ones
3330cdf0e10cSrcweir 		// an assertion will be triggered
makeStartPoint(const B2DPolygon & rCandidate,sal_uInt32 nIndexOfNewStatPoint)3331cdf0e10cSrcweir 		B2DPolygon makeStartPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndexOfNewStatPoint)
3332cdf0e10cSrcweir 		{
3333cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
3334cdf0e10cSrcweir 
3335cdf0e10cSrcweir 			if(nPointCount > 2 && nIndexOfNewStatPoint != 0 && nIndexOfNewStatPoint < nPointCount)
3336cdf0e10cSrcweir 			{
3337cdf0e10cSrcweir 				OSL_ENSURE(rCandidate.isClosed(), "makeStartPoint: only valid for closed polygons (!)");
3338cdf0e10cSrcweir 				B2DPolygon aRetval;
3339cdf0e10cSrcweir 
3340cdf0e10cSrcweir 				for(sal_uInt32 a(0); a < nPointCount; a++)
3341cdf0e10cSrcweir 				{
3342cdf0e10cSrcweir 					const sal_uInt32 nSourceIndex((a + nIndexOfNewStatPoint) % nPointCount);
3343cdf0e10cSrcweir 					aRetval.append(rCandidate.getB2DPoint(nSourceIndex));
3344cdf0e10cSrcweir 
3345cdf0e10cSrcweir 					if(rCandidate.areControlPointsUsed())
3346cdf0e10cSrcweir 					{
3347cdf0e10cSrcweir 						aRetval.setPrevControlPoint(a, rCandidate.getPrevControlPoint(nSourceIndex));
3348cdf0e10cSrcweir 						aRetval.setNextControlPoint(a, rCandidate.getNextControlPoint(nSourceIndex));
3349cdf0e10cSrcweir 					}
3350cdf0e10cSrcweir 				}
3351cdf0e10cSrcweir 
3352cdf0e10cSrcweir 				return aRetval;
3353cdf0e10cSrcweir 			}
3354cdf0e10cSrcweir 
3355cdf0e10cSrcweir 			return rCandidate;
3356cdf0e10cSrcweir 		}
3357cdf0e10cSrcweir 
createEdgesOfGivenLength(const B2DPolygon & rCandidate,double fLength,double fStart,double fEnd)3358cdf0e10cSrcweir 		B2DPolygon createEdgesOfGivenLength(const B2DPolygon& rCandidate, double fLength, double fStart, double fEnd)
3359cdf0e10cSrcweir 		{
3360cdf0e10cSrcweir 			B2DPolygon aRetval;
3361cdf0e10cSrcweir 
3362cdf0e10cSrcweir 			if(fLength < 0.0)
3363cdf0e10cSrcweir 			{
3364cdf0e10cSrcweir 				fLength = 0.0;
3365cdf0e10cSrcweir 			}
3366cdf0e10cSrcweir 
3367cdf0e10cSrcweir 			if(!fTools::equalZero(fLength))
3368cdf0e10cSrcweir 			{
3369cdf0e10cSrcweir 				if(fStart < 0.0)
3370cdf0e10cSrcweir 				{
3371cdf0e10cSrcweir 					fStart = 0.0;
3372cdf0e10cSrcweir 				}
3373cdf0e10cSrcweir 
3374cdf0e10cSrcweir 				if(fEnd < 0.0)
3375cdf0e10cSrcweir 				{
3376cdf0e10cSrcweir 					fEnd = 0.0;
3377cdf0e10cSrcweir 				}
3378cdf0e10cSrcweir 
3379cdf0e10cSrcweir 				if(fEnd < fStart)
3380cdf0e10cSrcweir 				{
3381cdf0e10cSrcweir 					fEnd = fStart;
3382cdf0e10cSrcweir 				}
3383cdf0e10cSrcweir 
3384cdf0e10cSrcweir 				// iterate and consume pieces with fLength. First subdivide to reduce input to line segments
3385cdf0e10cSrcweir 				const B2DPolygon aCandidate(rCandidate.areControlPointsUsed() ? rCandidate.getDefaultAdaptiveSubdivision() : rCandidate);
3386cdf0e10cSrcweir 				const sal_uInt32 nPointCount(aCandidate.count());
3387cdf0e10cSrcweir 
3388cdf0e10cSrcweir 				if(nPointCount > 1)
3389cdf0e10cSrcweir 				{
3390cdf0e10cSrcweir 					const bool bEndActive(!fTools::equalZero(fEnd));
3391cdf0e10cSrcweir 					const sal_uInt32 nEdgeCount(aCandidate.isClosed() ? nPointCount : nPointCount - 1);
3392cdf0e10cSrcweir 					B2DPoint aCurrent(aCandidate.getB2DPoint(0));
3393cdf0e10cSrcweir 					double fPositionInEdge(fStart);
3394cdf0e10cSrcweir 					double fAbsolutePosition(fStart);
3395cdf0e10cSrcweir 
3396cdf0e10cSrcweir 					for(sal_uInt32 a(0); a < nEdgeCount; a++)
3397cdf0e10cSrcweir 					{
3398cdf0e10cSrcweir 						const sal_uInt32 nNextIndex((a + 1) % nPointCount);
3399cdf0e10cSrcweir 						const B2DPoint aNext(aCandidate.getB2DPoint(nNextIndex));
3400cdf0e10cSrcweir 						const B2DVector aEdge(aNext - aCurrent);
3401cdf0e10cSrcweir 						double fEdgeLength(aEdge.getLength());
3402cdf0e10cSrcweir 
3403cdf0e10cSrcweir 						if(!fTools::equalZero(fEdgeLength))
3404cdf0e10cSrcweir 						{
3405cdf0e10cSrcweir 							while(fTools::less(fPositionInEdge, fEdgeLength))
3406cdf0e10cSrcweir 							{
3407cdf0e10cSrcweir 								// move position on edge forward as long as on edge
3408cdf0e10cSrcweir 								const double fScalar(fPositionInEdge / fEdgeLength);
3409cdf0e10cSrcweir 								aRetval.append(aCurrent + (aEdge * fScalar));
3410cdf0e10cSrcweir 								fPositionInEdge += fLength;
3411cdf0e10cSrcweir 
3412cdf0e10cSrcweir 								if(bEndActive)
3413cdf0e10cSrcweir 								{
3414cdf0e10cSrcweir 									fAbsolutePosition += fLength;
3415cdf0e10cSrcweir 
3416cdf0e10cSrcweir 									if(fTools::more(fAbsolutePosition, fEnd))
3417cdf0e10cSrcweir 									{
3418cdf0e10cSrcweir 										break;
3419cdf0e10cSrcweir 									}
3420cdf0e10cSrcweir 								}
3421cdf0e10cSrcweir 							}
3422cdf0e10cSrcweir 
3423cdf0e10cSrcweir 							// substract length of current edge
3424cdf0e10cSrcweir 							fPositionInEdge -= fEdgeLength;
3425cdf0e10cSrcweir 						}
3426cdf0e10cSrcweir 
3427cdf0e10cSrcweir 						if(bEndActive && fTools::more(fAbsolutePosition, fEnd))
3428cdf0e10cSrcweir 						{
3429cdf0e10cSrcweir 							break;
3430cdf0e10cSrcweir 						}
3431cdf0e10cSrcweir 
3432cdf0e10cSrcweir 						// prepare next step
3433cdf0e10cSrcweir 						aCurrent = aNext;
3434cdf0e10cSrcweir 					}
3435cdf0e10cSrcweir 
3436cdf0e10cSrcweir 					// keep closed state
3437cdf0e10cSrcweir 					aRetval.setClosed(aCandidate.isClosed());
3438cdf0e10cSrcweir 				}
3439cdf0e10cSrcweir 				else
3440cdf0e10cSrcweir 				{
3441cdf0e10cSrcweir 					// source polygon has only one point, return unchanged
3442cdf0e10cSrcweir 					aRetval = aCandidate;
3443cdf0e10cSrcweir 				}
3444cdf0e10cSrcweir 			}
3445cdf0e10cSrcweir 
3446cdf0e10cSrcweir 			return aRetval;
3447cdf0e10cSrcweir 		}
3448cdf0e10cSrcweir 
createWaveline(const B2DPolygon & rCandidate,double fWaveWidth,double fWaveHeight)3449cdf0e10cSrcweir 		B2DPolygon createWaveline(const B2DPolygon& rCandidate, double fWaveWidth, double fWaveHeight)
3450cdf0e10cSrcweir 		{
3451cdf0e10cSrcweir 			B2DPolygon aRetval;
3452cdf0e10cSrcweir 
3453cdf0e10cSrcweir 			if(fWaveWidth < 0.0)
3454cdf0e10cSrcweir 			{
3455cdf0e10cSrcweir 				fWaveWidth = 0.0;
3456cdf0e10cSrcweir 			}
3457cdf0e10cSrcweir 
3458cdf0e10cSrcweir 			if(fWaveHeight < 0.0)
3459cdf0e10cSrcweir 			{
3460cdf0e10cSrcweir 				fWaveHeight = 0.0;
3461cdf0e10cSrcweir 			}
3462cdf0e10cSrcweir 
3463cdf0e10cSrcweir 			const bool bHasWidth(!fTools::equalZero(fWaveWidth));
3464cdf0e10cSrcweir 			const bool bHasHeight(!fTools::equalZero(fWaveHeight));
3465cdf0e10cSrcweir 
3466cdf0e10cSrcweir 			if(bHasWidth)
3467cdf0e10cSrcweir 			{
3468cdf0e10cSrcweir 				if(bHasHeight)
3469cdf0e10cSrcweir 				{
3470cdf0e10cSrcweir 					// width and height, create waveline. First subdivide to reduce input to line segments
3471cdf0e10cSrcweir 					// of WaveWidth. Last segment may be missing. If this turns out to be a problem, it
3472cdf0e10cSrcweir 					// may be added here again using the original last point from rCandidate. It may
3473cdf0e10cSrcweir 					// also be the case that rCandidate was closed. To simplify things it is handled here
3474cdf0e10cSrcweir 					// as if it was opened.
3475cdf0e10cSrcweir 					// Result from createEdgesOfGivenLength contains no curved segments, handle as straight
3476cdf0e10cSrcweir 					// edges.
3477cdf0e10cSrcweir 					const B2DPolygon aEqualLenghEdges(createEdgesOfGivenLength(rCandidate, fWaveWidth));
3478cdf0e10cSrcweir 					const sal_uInt32 nPointCount(aEqualLenghEdges.count());
3479cdf0e10cSrcweir 
3480cdf0e10cSrcweir 					if(nPointCount > 1)
3481cdf0e10cSrcweir 					{
3482cdf0e10cSrcweir 						// iterate over straight edges, add start point
3483cdf0e10cSrcweir 						B2DPoint aCurrent(aEqualLenghEdges.getB2DPoint(0));
3484cdf0e10cSrcweir 						aRetval.append(aCurrent);
3485cdf0e10cSrcweir 
3486cdf0e10cSrcweir 						for(sal_uInt32 a(0); a < nPointCount - 1; a++)
3487cdf0e10cSrcweir 						{
3488cdf0e10cSrcweir 							const sal_uInt32 nNextIndex((a + 1) % nPointCount);
3489cdf0e10cSrcweir 							const B2DPoint aNext(aEqualLenghEdges.getB2DPoint(nNextIndex));
3490cdf0e10cSrcweir 							const B2DVector aEdge(aNext - aCurrent);
3491cdf0e10cSrcweir 							const B2DVector aPerpendicular(getNormalizedPerpendicular(aEdge));
3492cdf0e10cSrcweir                             const B2DVector aControlOffset((aEdge * 0.467308) - (aPerpendicular * fWaveHeight));
3493cdf0e10cSrcweir 
3494cdf0e10cSrcweir 							// add curve segment
3495cdf0e10cSrcweir 							aRetval.appendBezierSegment(
3496cdf0e10cSrcweir 								aCurrent + aControlOffset,
3497cdf0e10cSrcweir 								aNext - aControlOffset,
3498cdf0e10cSrcweir 								aNext);
3499cdf0e10cSrcweir 
3500cdf0e10cSrcweir 							// prepare next step
3501cdf0e10cSrcweir 							aCurrent = aNext;
3502cdf0e10cSrcweir 						}
3503cdf0e10cSrcweir 					}
3504cdf0e10cSrcweir 				}
3505cdf0e10cSrcweir 				else
3506cdf0e10cSrcweir 				{
3507cdf0e10cSrcweir 					// width but no height -> return original polygon
3508cdf0e10cSrcweir 					aRetval = rCandidate;
3509cdf0e10cSrcweir 				}
3510cdf0e10cSrcweir 			}
3511cdf0e10cSrcweir 			else
3512cdf0e10cSrcweir 			{
3513cdf0e10cSrcweir 				// no width -> no waveline, stay empty and return
3514cdf0e10cSrcweir 			}
3515cdf0e10cSrcweir 
3516cdf0e10cSrcweir 			return aRetval;
3517cdf0e10cSrcweir 		}
3518cdf0e10cSrcweir 
3519cdf0e10cSrcweir         //////////////////////////////////////////////////////////////////////
3520cdf0e10cSrcweir 		// comparators with tolerance for 2D Polygons
3521cdf0e10cSrcweir 
equal(const B2DPolygon & rCandidateA,const B2DPolygon & rCandidateB,const double & rfSmallValue)3522cdf0e10cSrcweir 		bool equal(const B2DPolygon& rCandidateA, const B2DPolygon& rCandidateB, const double& rfSmallValue)
3523cdf0e10cSrcweir 		{
3524cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidateA.count());
3525cdf0e10cSrcweir 
3526cdf0e10cSrcweir 			if(nPointCount != rCandidateB.count())
3527cdf0e10cSrcweir 				return false;
3528cdf0e10cSrcweir 
3529cdf0e10cSrcweir 			const bool bClosed(rCandidateA.isClosed());
3530cdf0e10cSrcweir 
3531cdf0e10cSrcweir 			if(bClosed != rCandidateB.isClosed())
3532cdf0e10cSrcweir 				return false;
3533cdf0e10cSrcweir 
3534cdf0e10cSrcweir 			const bool bAreControlPointsUsed(rCandidateA.areControlPointsUsed());
3535cdf0e10cSrcweir 
3536cdf0e10cSrcweir 			if(bAreControlPointsUsed != rCandidateB.areControlPointsUsed())
3537cdf0e10cSrcweir 				return false;
3538cdf0e10cSrcweir 
3539cdf0e10cSrcweir 			for(sal_uInt32 a(0); a < nPointCount; a++)
3540cdf0e10cSrcweir 			{
3541cdf0e10cSrcweir 				const B2DPoint aPoint(rCandidateA.getB2DPoint(a));
3542cdf0e10cSrcweir 
3543cdf0e10cSrcweir 				if(!aPoint.equal(rCandidateB.getB2DPoint(a), rfSmallValue))
3544cdf0e10cSrcweir 					return false;
3545cdf0e10cSrcweir 
3546cdf0e10cSrcweir 				if(bAreControlPointsUsed)
3547cdf0e10cSrcweir 				{
3548cdf0e10cSrcweir 					const basegfx::B2DPoint aPrev(rCandidateA.getPrevControlPoint(a));
3549cdf0e10cSrcweir 
3550cdf0e10cSrcweir 					if(!aPrev.equal(rCandidateB.getPrevControlPoint(a), rfSmallValue))
3551cdf0e10cSrcweir 						return false;
3552cdf0e10cSrcweir 
3553cdf0e10cSrcweir 					const basegfx::B2DPoint aNext(rCandidateA.getNextControlPoint(a));
3554cdf0e10cSrcweir 
3555cdf0e10cSrcweir 					if(!aNext.equal(rCandidateB.getNextControlPoint(a), rfSmallValue))
3556cdf0e10cSrcweir 						return false;
3557cdf0e10cSrcweir 				}
3558cdf0e10cSrcweir 			}
3559cdf0e10cSrcweir 
3560cdf0e10cSrcweir 			return true;
3561cdf0e10cSrcweir 		}
3562cdf0e10cSrcweir 
equal(const B2DPolygon & rCandidateA,const B2DPolygon & rCandidateB)3563cdf0e10cSrcweir 		bool equal(const B2DPolygon& rCandidateA, const B2DPolygon& rCandidateB)
3564cdf0e10cSrcweir 		{
3565cdf0e10cSrcweir 			const double fSmallValue(fTools::getSmallValue());
3566cdf0e10cSrcweir 
3567cdf0e10cSrcweir 			return equal(rCandidateA, rCandidateB, fSmallValue);
3568cdf0e10cSrcweir 		}
3569cdf0e10cSrcweir 
3570cdf0e10cSrcweir 		// snap points of horizontal or vertical edges to discrete values
snapPointsOfHorizontalOrVerticalEdges(const B2DPolygon & rCandidate)3571cdf0e10cSrcweir 		B2DPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolygon& rCandidate)
3572cdf0e10cSrcweir 		{
3573cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
3574cdf0e10cSrcweir 
3575cdf0e10cSrcweir 			if(nPointCount > 1)
3576cdf0e10cSrcweir 			{
3577cdf0e10cSrcweir 				// Start by copying the source polygon to get a writeable copy. The closed state is
3578cdf0e10cSrcweir 				// copied by aRetval's initialisation, too, so no need to copy it in this method
3579cdf0e10cSrcweir 				B2DPolygon aRetval(rCandidate);
3580cdf0e10cSrcweir 
3581cdf0e10cSrcweir 				// prepare geometry data. Get rounded from original
3582cdf0e10cSrcweir                 B2ITuple aPrevTuple(basegfx::fround(rCandidate.getB2DPoint(nPointCount - 1)));
3583cdf0e10cSrcweir 				B2DPoint aCurrPoint(rCandidate.getB2DPoint(0));
3584cdf0e10cSrcweir 				B2ITuple aCurrTuple(basegfx::fround(aCurrPoint));
3585cdf0e10cSrcweir 
3586cdf0e10cSrcweir 				// loop over all points. This will also snap the implicit closing edge
3587cdf0e10cSrcweir 				// even when not closed, but that's no problem here
3588cdf0e10cSrcweir 				for(sal_uInt32 a(0); a < nPointCount; a++)
3589cdf0e10cSrcweir 				{
3590cdf0e10cSrcweir 					// get next point. Get rounded from original
3591cdf0e10cSrcweir                     const bool bLastRun(a + 1 == nPointCount);
3592cdf0e10cSrcweir                     const sal_uInt32 nNextIndex(bLastRun ? 0 : a + 1);
3593cdf0e10cSrcweir 					const B2DPoint aNextPoint(rCandidate.getB2DPoint(nNextIndex));
3594cdf0e10cSrcweir 					const B2ITuple aNextTuple(basegfx::fround(aNextPoint));
3595cdf0e10cSrcweir 
3596cdf0e10cSrcweir 					// get the states
3597cdf0e10cSrcweir 					const bool bPrevVertical(aPrevTuple.getX() == aCurrTuple.getX());
3598cdf0e10cSrcweir 					const bool bNextVertical(aNextTuple.getX() == aCurrTuple.getX());
3599cdf0e10cSrcweir 					const bool bPrevHorizontal(aPrevTuple.getY() == aCurrTuple.getY());
3600cdf0e10cSrcweir 					const bool bNextHorizontal(aNextTuple.getY() == aCurrTuple.getY());
3601cdf0e10cSrcweir 					const bool bSnapX(bPrevVertical || bNextVertical);
3602cdf0e10cSrcweir 					const bool bSnapY(bPrevHorizontal || bNextHorizontal);
3603cdf0e10cSrcweir 
3604cdf0e10cSrcweir 					if(bSnapX || bSnapY)
3605cdf0e10cSrcweir 					{
3606cdf0e10cSrcweir 						const B2DPoint aSnappedPoint(
3607cdf0e10cSrcweir 							bSnapX ? aCurrTuple.getX() : aCurrPoint.getX(),
3608cdf0e10cSrcweir 							bSnapY ? aCurrTuple.getY() : aCurrPoint.getY());
3609cdf0e10cSrcweir 
3610cdf0e10cSrcweir 						aRetval.setB2DPoint(a, aSnappedPoint);
3611cdf0e10cSrcweir 					}
3612cdf0e10cSrcweir 
3613cdf0e10cSrcweir 					// prepare next point
3614cdf0e10cSrcweir                     if(!bLastRun)
3615cdf0e10cSrcweir                     {
3616cdf0e10cSrcweir     					aPrevTuple = aCurrTuple;
3617cdf0e10cSrcweir 	    				aCurrPoint = aNextPoint;
3618cdf0e10cSrcweir 		    			aCurrTuple = aNextTuple;
3619cdf0e10cSrcweir                     }
3620cdf0e10cSrcweir 				}
3621cdf0e10cSrcweir 
3622cdf0e10cSrcweir 				return aRetval;
3623cdf0e10cSrcweir 			}
3624cdf0e10cSrcweir 			else
3625cdf0e10cSrcweir 			{
3626cdf0e10cSrcweir 				return rCandidate;
3627cdf0e10cSrcweir 			}
3628cdf0e10cSrcweir 		}
3629cdf0e10cSrcweir 
containsOnlyHorizontalAndVerticalEdges(const B2DPolygon & rCandidate)3630d8ed516eSArmin Le Grand         bool containsOnlyHorizontalAndVerticalEdges(const B2DPolygon& rCandidate)
3631d8ed516eSArmin Le Grand         {
3632d8ed516eSArmin Le Grand             if(rCandidate.areControlPointsUsed())
3633d8ed516eSArmin Le Grand             {
3634d8ed516eSArmin Le Grand                 return false;
3635d8ed516eSArmin Le Grand             }
3636d8ed516eSArmin Le Grand 
3637d8ed516eSArmin Le Grand             const sal_uInt32 nPointCount(rCandidate.count());
3638d8ed516eSArmin Le Grand 
3639d8ed516eSArmin Le Grand             if(nPointCount < 2)
3640d8ed516eSArmin Le Grand             {
3641d8ed516eSArmin Le Grand                 return true;
3642d8ed516eSArmin Le Grand             }
3643d8ed516eSArmin Le Grand 
3644d8ed516eSArmin Le Grand             const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount + 1 : nPointCount);
3645d8ed516eSArmin Le Grand             basegfx::B2DPoint aLast(rCandidate.getB2DPoint(0));
3646d8ed516eSArmin Le Grand 
3647d8ed516eSArmin Le Grand             for(sal_uInt32 a(1); a < nEdgeCount; a++)
3648d8ed516eSArmin Le Grand             {
3649d8ed516eSArmin Le Grand                 const sal_uInt32 nNextIndex(a % nPointCount);
3650d8ed516eSArmin Le Grand                 const basegfx::B2DPoint aCurrent(rCandidate.getB2DPoint(nNextIndex));
3651d8ed516eSArmin Le Grand 
3652d8ed516eSArmin Le Grand                 if(!basegfx::fTools::equal(aLast.getX(), aCurrent.getX()) && !basegfx::fTools::equal(aLast.getY(), aCurrent.getY()))
3653d8ed516eSArmin Le Grand                 {
3654d8ed516eSArmin Le Grand                     return false;
3655d8ed516eSArmin Le Grand                 }
3656d8ed516eSArmin Le Grand 
3657d8ed516eSArmin Le Grand                 aLast = aCurrent;
3658d8ed516eSArmin Le Grand             }
3659d8ed516eSArmin Le Grand 
3660d8ed516eSArmin Le Grand             return true;
3661d8ed516eSArmin Le Grand         }
3662d8ed516eSArmin Le Grand 
getTangentEnteringPoint(const B2DPolygon & rCandidate,sal_uInt32 nIndex)3663facb0eb6SArmin Le Grand         B2DVector getTangentEnteringPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndex)
3664facb0eb6SArmin Le Grand         {
3665facb0eb6SArmin Le Grand             B2DVector aRetval(0.0, 0.0);
3666facb0eb6SArmin Le Grand             const sal_uInt32 nCount(rCandidate.count());
3667facb0eb6SArmin Le Grand 
3668facb0eb6SArmin Le Grand             if(nIndex >= nCount)
3669facb0eb6SArmin Le Grand             {
3670facb0eb6SArmin Le Grand                 // out of range
3671facb0eb6SArmin Le Grand                 return aRetval;
3672facb0eb6SArmin Le Grand             }
3673facb0eb6SArmin Le Grand 
3674facb0eb6SArmin Le Grand             // start immediately at prev point compared to nIndex
3675facb0eb6SArmin Le Grand             const bool bClosed(rCandidate.isClosed());
3676facb0eb6SArmin Le Grand             sal_uInt32 nPrev(bClosed ? (nIndex + nCount - 1) % nCount : nIndex ? nIndex - 1 : nIndex);
3677facb0eb6SArmin Le Grand 
3678facb0eb6SArmin Le Grand             if(nPrev == nIndex)
3679facb0eb6SArmin Le Grand             {
3680facb0eb6SArmin Le Grand                 // no previous, done
3681facb0eb6SArmin Le Grand                 return aRetval;
3682facb0eb6SArmin Le Grand             }
3683facb0eb6SArmin Le Grand 
3684facb0eb6SArmin Le Grand             B2DCubicBezier aSegment;
3685facb0eb6SArmin Le Grand 
3686facb0eb6SArmin Le Grand             // go backward in the polygon; if closed, maximal back to start index (nIndex); if not closed,
3687facb0eb6SArmin Le Grand             // until zero. Use nIndex as stop criteria
3688facb0eb6SArmin Le Grand             while(nPrev != nIndex)
3689facb0eb6SArmin Le Grand             {
3690facb0eb6SArmin Le Grand                 // get BezierSegment and tangent at the *end* of segment
3691facb0eb6SArmin Le Grand                 rCandidate.getBezierSegment(nPrev, aSegment);
3692facb0eb6SArmin Le Grand                 aRetval = aSegment.getTangent(1.0);
3693facb0eb6SArmin Le Grand 
3694facb0eb6SArmin Le Grand                 if(!aRetval.equalZero())
3695facb0eb6SArmin Le Grand                 {
3696facb0eb6SArmin Le Grand                     // if we have a tangent, return it
3697facb0eb6SArmin Le Grand                     return aRetval;
3698facb0eb6SArmin Le Grand                 }
3699facb0eb6SArmin Le Grand 
3700facb0eb6SArmin Le Grand                 // prepare index before checked one
3701facb0eb6SArmin Le Grand                 nPrev = bClosed ? (nPrev + nCount - 1) % nCount : nPrev ? nPrev - 1 : nIndex;
3702facb0eb6SArmin Le Grand             }
3703facb0eb6SArmin Le Grand 
3704facb0eb6SArmin Le Grand             return aRetval;
3705facb0eb6SArmin Le Grand         }
3706facb0eb6SArmin Le Grand 
getTangentLeavingPoint(const B2DPolygon & rCandidate,sal_uInt32 nIndex)3707facb0eb6SArmin Le Grand         B2DVector getTangentLeavingPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndex)
3708facb0eb6SArmin Le Grand         {
3709facb0eb6SArmin Le Grand             B2DVector aRetval(0.0, 0.0);
3710facb0eb6SArmin Le Grand             const sal_uInt32 nCount(rCandidate.count());
3711facb0eb6SArmin Le Grand 
3712facb0eb6SArmin Le Grand             if(nIndex >= nCount)
3713facb0eb6SArmin Le Grand             {
3714facb0eb6SArmin Le Grand                 // out of range
3715facb0eb6SArmin Le Grand                 return aRetval;
3716facb0eb6SArmin Le Grand             }
3717facb0eb6SArmin Le Grand 
3718facb0eb6SArmin Le Grand             // start at nIndex
3719facb0eb6SArmin Le Grand             const bool bClosed(rCandidate.isClosed());
3720facb0eb6SArmin Le Grand             sal_uInt32 nCurrent(nIndex);
3721facb0eb6SArmin Le Grand             B2DCubicBezier aSegment;
3722facb0eb6SArmin Le Grand 
3723facb0eb6SArmin Le Grand             // go forward; if closed, do this until once around and back at start index (nIndex); if not
3724facb0eb6SArmin Le Grand             // closed, until last point (nCount - 1). Use nIndex as stop criteria
3725facb0eb6SArmin Le Grand             do
3726facb0eb6SArmin Le Grand             {
3727facb0eb6SArmin Le Grand                 // get BezierSegment and tangent at the *beginning* of segment
3728facb0eb6SArmin Le Grand                 rCandidate.getBezierSegment(nCurrent, aSegment);
3729facb0eb6SArmin Le Grand                 aRetval = aSegment.getTangent(0.0);
3730facb0eb6SArmin Le Grand 
3731facb0eb6SArmin Le Grand                 if(!aRetval.equalZero())
3732facb0eb6SArmin Le Grand                 {
3733facb0eb6SArmin Le Grand                     // if we have a tangent, return it
3734facb0eb6SArmin Le Grand                     return aRetval;
3735facb0eb6SArmin Le Grand                 }
3736facb0eb6SArmin Le Grand 
3737facb0eb6SArmin Le Grand                 // prepare next index
3738facb0eb6SArmin Le Grand                 nCurrent = bClosed ? (nCurrent + 1) % nCount : nCurrent + 1 < nCount ? nCurrent + 1 : nIndex;
3739facb0eb6SArmin Le Grand             }
3740facb0eb6SArmin Le Grand             while(nCurrent != nIndex);
3741facb0eb6SArmin Le Grand 
3742facb0eb6SArmin Le Grand             return aRetval;
3743facb0eb6SArmin Le Grand         }
3744facb0eb6SArmin Le Grand 
3745*1f882ec4SArmin Le Grand         //////////////////////////////////////////////////////////////////////////////
3746*1f882ec4SArmin Le Grand         // converters for com::sun::star::drawing::PointSequence
3747*1f882ec4SArmin Le Grand 
UnoPointSequenceToB2DPolygon(const com::sun::star::drawing::PointSequence & rPointSequenceSource,bool bCheckClosed)3748*1f882ec4SArmin Le Grand         B2DPolygon UnoPointSequenceToB2DPolygon(
3749*1f882ec4SArmin Le Grand             const com::sun::star::drawing::PointSequence& rPointSequenceSource,
3750*1f882ec4SArmin Le Grand             bool bCheckClosed)
3751*1f882ec4SArmin Le Grand         {
3752*1f882ec4SArmin Le Grand             B2DPolygon aRetval;
3753*1f882ec4SArmin Le Grand             const sal_uInt32 nLength(rPointSequenceSource.getLength());
3754*1f882ec4SArmin Le Grand 
3755*1f882ec4SArmin Le Grand             if(nLength)
3756*1f882ec4SArmin Le Grand             {
3757*1f882ec4SArmin Le Grand                 aRetval.reserve(nLength);
3758*1f882ec4SArmin Le Grand                 const com::sun::star::awt::Point* pArray = rPointSequenceSource.getConstArray();
3759*1f882ec4SArmin Le Grand                 const com::sun::star::awt::Point* pArrayEnd = pArray + rPointSequenceSource.getLength();
3760*1f882ec4SArmin Le Grand 
3761*1f882ec4SArmin Le Grand                 for(;pArray != pArrayEnd; pArray++)
3762*1f882ec4SArmin Le Grand                 {
3763*1f882ec4SArmin Le Grand                     aRetval.append(B2DPoint(pArray->X, pArray->Y));
3764*1f882ec4SArmin Le Grand                 }
3765*1f882ec4SArmin Le Grand 
3766*1f882ec4SArmin Le Grand                 if(bCheckClosed)
3767*1f882ec4SArmin Le Grand                 {
3768*1f882ec4SArmin Le Grand                     // check for closed state flag
3769*1f882ec4SArmin Le Grand                     tools::checkClosed(aRetval);
3770*1f882ec4SArmin Le Grand                 }
3771*1f882ec4SArmin Le Grand             }
3772*1f882ec4SArmin Le Grand 
3773*1f882ec4SArmin Le Grand             return aRetval;
3774*1f882ec4SArmin Le Grand         }
3775*1f882ec4SArmin Le Grand 
B2DPolygonToUnoPointSequence(const B2DPolygon & rPolygon,com::sun::star::drawing::PointSequence & rPointSequenceRetval)3776*1f882ec4SArmin Le Grand         void B2DPolygonToUnoPointSequence(
3777*1f882ec4SArmin Le Grand             const B2DPolygon& rPolygon,
3778*1f882ec4SArmin Le Grand             com::sun::star::drawing::PointSequence& rPointSequenceRetval)
3779*1f882ec4SArmin Le Grand         {
3780*1f882ec4SArmin Le Grand             B2DPolygon aPolygon(rPolygon);
3781*1f882ec4SArmin Le Grand 
3782*1f882ec4SArmin Le Grand             if(aPolygon.areControlPointsUsed())
3783*1f882ec4SArmin Le Grand             {
3784*1f882ec4SArmin Le Grand                 OSL_ENSURE(false, "B2DPolygonToUnoPointSequence: Source contains bezier segments, wrong UNO API data type may be used (!)");
3785*1f882ec4SArmin Le Grand                 aPolygon = aPolygon.getDefaultAdaptiveSubdivision();
3786*1f882ec4SArmin Le Grand             }
3787*1f882ec4SArmin Le Grand 
3788*1f882ec4SArmin Le Grand             const sal_uInt32 nPointCount(aPolygon.count());
3789*1f882ec4SArmin Le Grand 
3790*1f882ec4SArmin Le Grand             if(nPointCount)
3791*1f882ec4SArmin Le Grand             {
3792*1f882ec4SArmin Le Grand                 // Take closed state into account, the API polygon still uses the old closed definition
3793*1f882ec4SArmin Le Grand                 // with last/first point are identical (cannot hold information about open polygons with identical
3794*1f882ec4SArmin Le Grand                 // first and last point, though)
3795*1f882ec4SArmin Le Grand                 const bool bIsClosed(aPolygon.isClosed());
3796*1f882ec4SArmin Le Grand 
3797*1f882ec4SArmin Le Grand                 rPointSequenceRetval.realloc(bIsClosed ? nPointCount + 1 : nPointCount);
3798*1f882ec4SArmin Le Grand                 com::sun::star::awt::Point* pSequence = rPointSequenceRetval.getArray();
3799*1f882ec4SArmin Le Grand 
3800*1f882ec4SArmin Le Grand                 for(sal_uInt32 b(0); b < nPointCount; b++)
3801*1f882ec4SArmin Le Grand                 {
3802*1f882ec4SArmin Le Grand                     const B2DPoint aPoint(aPolygon.getB2DPoint(b));
3803*1f882ec4SArmin Le Grand                     const com::sun::star::awt::Point aAPIPoint(fround(aPoint.getX()), fround(aPoint.getY()));
3804*1f882ec4SArmin Le Grand 
3805*1f882ec4SArmin Le Grand                     *pSequence = aAPIPoint;
3806*1f882ec4SArmin Le Grand                     pSequence++;
3807*1f882ec4SArmin Le Grand                 }
3808*1f882ec4SArmin Le Grand 
3809*1f882ec4SArmin Le Grand                 // copy first point if closed
3810*1f882ec4SArmin Le Grand                 if(bIsClosed)
3811*1f882ec4SArmin Le Grand                 {
3812*1f882ec4SArmin Le Grand                     *pSequence = *rPointSequenceRetval.getArray();
3813*1f882ec4SArmin Le Grand                 }
3814*1f882ec4SArmin Le Grand             }
3815*1f882ec4SArmin Le Grand             else
3816*1f882ec4SArmin Le Grand             {
3817*1f882ec4SArmin Le Grand                 rPointSequenceRetval.realloc(0);
3818*1f882ec4SArmin Le Grand             }
3819*1f882ec4SArmin Le Grand         }
3820*1f882ec4SArmin Le Grand 
3821*1f882ec4SArmin Le Grand         //////////////////////////////////////////////////////////////////////////////
3822*1f882ec4SArmin Le Grand         // converters for com::sun::star::drawing::PointSequence and
3823*1f882ec4SArmin Le Grand         // com::sun::star::drawing::FlagSequence to B2DPolygon (curved polygons)
3824*1f882ec4SArmin Le Grand 
UnoPolygonBezierCoordsToB2DPolygon(const com::sun::star::drawing::PointSequence & rPointSequenceSource,const com::sun::star::drawing::FlagSequence & rFlagSequenceSource,bool bCheckClosed)3825*1f882ec4SArmin Le Grand         B2DPolygon UnoPolygonBezierCoordsToB2DPolygon(
3826*1f882ec4SArmin Le Grand             const com::sun::star::drawing::PointSequence& rPointSequenceSource,
3827*1f882ec4SArmin Le Grand             const com::sun::star::drawing::FlagSequence& rFlagSequenceSource,
3828*1f882ec4SArmin Le Grand             bool bCheckClosed)
3829*1f882ec4SArmin Le Grand         {
3830*1f882ec4SArmin Le Grand             const sal_uInt32 nCount((sal_uInt32)rPointSequenceSource.getLength());
3831*1f882ec4SArmin Le Grand             OSL_ENSURE(nCount == (sal_uInt32)rFlagSequenceSource.getLength(),
3832*1f882ec4SArmin Le Grand                 "UnoPolygonBezierCoordsToB2DPolygon: Unequal count of Points and Flags (!)");
3833*1f882ec4SArmin Le Grand 
3834*1f882ec4SArmin Le Grand             // prepare new polygon
3835*1f882ec4SArmin Le Grand             B2DPolygon aRetval;
3836*1f882ec4SArmin Le Grand             const com::sun::star::awt::Point* pPointSequence = rPointSequenceSource.getConstArray();
3837*1f882ec4SArmin Le Grand             const com::sun::star::drawing::PolygonFlags* pFlagSequence = rFlagSequenceSource.getConstArray();
3838*1f882ec4SArmin Le Grand 
3839*1f882ec4SArmin Le Grand             // get first point and flag
3840*1f882ec4SArmin Le Grand             B2DPoint aNewCoordinatePair(pPointSequence->X, pPointSequence->Y); pPointSequence++;
3841*1f882ec4SArmin Le Grand             com::sun::star::drawing::PolygonFlags ePolygonFlag(*pFlagSequence); pFlagSequence++;
3842*1f882ec4SArmin Le Grand             B2DPoint aControlA;
3843*1f882ec4SArmin Le Grand             B2DPoint aControlB;
3844*1f882ec4SArmin Le Grand 
3845*1f882ec4SArmin Le Grand             // first point is not allowed to be a control point
3846*1f882ec4SArmin Le Grand             OSL_ENSURE(com::sun::star::drawing::PolygonFlags_CONTROL != ePolygonFlag,
3847*1f882ec4SArmin Le Grand                 "UnoPolygonBezierCoordsToB2DPolygon: Start point is a control point, illegal input polygon (!)");
3848*1f882ec4SArmin Le Grand 
3849*1f882ec4SArmin Le Grand             // add first point as start point
3850*1f882ec4SArmin Le Grand             aRetval.append(aNewCoordinatePair);
3851*1f882ec4SArmin Le Grand 
3852*1f882ec4SArmin Le Grand             for(sal_uInt32 b(1); b < nCount;)
3853*1f882ec4SArmin Le Grand             {
3854*1f882ec4SArmin Le Grand                 // prepare loop
3855*1f882ec4SArmin Le Grand                 bool bControlA(false);
3856*1f882ec4SArmin Le Grand                 bool bControlB(false);
3857*1f882ec4SArmin Le Grand 
3858*1f882ec4SArmin Le Grand                 // get next point and flag
3859*1f882ec4SArmin Le Grand                 aNewCoordinatePair = B2DPoint(pPointSequence->X, pPointSequence->Y);
3860*1f882ec4SArmin Le Grand                 ePolygonFlag = *pFlagSequence;
3861*1f882ec4SArmin Le Grand                 pPointSequence++; pFlagSequence++; b++;
3862*1f882ec4SArmin Le Grand 
3863*1f882ec4SArmin Le Grand                 if(b < nCount && com::sun::star::drawing::PolygonFlags_CONTROL == ePolygonFlag)
3864*1f882ec4SArmin Le Grand                 {
3865*1f882ec4SArmin Le Grand                     aControlA = aNewCoordinatePair;
3866*1f882ec4SArmin Le Grand                     bControlA = true;
3867*1f882ec4SArmin Le Grand 
3868*1f882ec4SArmin Le Grand                     // get next point and flag
3869*1f882ec4SArmin Le Grand                     aNewCoordinatePair = B2DPoint(pPointSequence->X, pPointSequence->Y);
3870*1f882ec4SArmin Le Grand                     ePolygonFlag = *pFlagSequence;
3871*1f882ec4SArmin Le Grand                     pPointSequence++; pFlagSequence++; b++;
3872*1f882ec4SArmin Le Grand                 }
3873*1f882ec4SArmin Le Grand 
3874*1f882ec4SArmin Le Grand                 if(b < nCount && com::sun::star::drawing::PolygonFlags_CONTROL == ePolygonFlag)
3875*1f882ec4SArmin Le Grand                 {
3876*1f882ec4SArmin Le Grand                     aControlB = aNewCoordinatePair;
3877*1f882ec4SArmin Le Grand                     bControlB = true;
3878*1f882ec4SArmin Le Grand 
3879*1f882ec4SArmin Le Grand                     // get next point and flag
3880*1f882ec4SArmin Le Grand                     aNewCoordinatePair = B2DPoint(pPointSequence->X, pPointSequence->Y);
3881*1f882ec4SArmin Le Grand                     ePolygonFlag = *pFlagSequence;
3882*1f882ec4SArmin Le Grand                     pPointSequence++; pFlagSequence++; b++;
3883*1f882ec4SArmin Le Grand                 }
3884*1f882ec4SArmin Le Grand 
3885*1f882ec4SArmin Le Grand                 // two or no control points are consumed, another one would be an error.
3886*1f882ec4SArmin Le Grand                 // It's also an error if only one control point was read
3887*1f882ec4SArmin Le Grand                 OSL_ENSURE(com::sun::star::drawing::PolygonFlags_CONTROL != ePolygonFlag && bControlA == bControlB,
3888*1f882ec4SArmin Le Grand                     "UnoPolygonBezierCoordsToB2DPolygon: Illegal source polygon (!)");
3889*1f882ec4SArmin Le Grand 
3890*1f882ec4SArmin Le Grand                 // the previous writes used the B2DPolyPoygon -> PolyPolygon converter
3891*1f882ec4SArmin Le Grand                 // which did not create minimal PolyPolygons, but created all control points
3892*1f882ec4SArmin Le Grand                 // as null vectors (identical points). Because of the former P(CA)(CB)-norm of
3893*1f882ec4SArmin Le Grand                 // B2DPolygon and it's unused sign of being the zero-vector and CA and CB being
3894*1f882ec4SArmin Le Grand                 // relative to P, an empty edge was exported as P == CA == CB. Luckily, the new
3895*1f882ec4SArmin Le Grand                 // export format can be read without errors by the old OOo-versions, so we need only
3896*1f882ec4SArmin Le Grand                 // to correct here at read and do not need to export a wrong but compatible version
3897*1f882ec4SArmin Le Grand                 // for the future.
3898*1f882ec4SArmin Le Grand                 if(bControlA
3899*1f882ec4SArmin Le Grand                     && aControlA.equal(aControlB)
3900*1f882ec4SArmin Le Grand                     && aControlA.equal(aRetval.getB2DPoint(aRetval.count() - 1)))
3901*1f882ec4SArmin Le Grand                 {
3902*1f882ec4SArmin Le Grand                     bControlA = bControlB = false;
3903*1f882ec4SArmin Le Grand                 }
3904*1f882ec4SArmin Le Grand 
3905*1f882ec4SArmin Le Grand                 if(bControlA)
3906*1f882ec4SArmin Le Grand                 {
3907*1f882ec4SArmin Le Grand                     // add bezier edge
3908*1f882ec4SArmin Le Grand                     aRetval.appendBezierSegment(aControlA, aControlB, aNewCoordinatePair);
3909*1f882ec4SArmin Le Grand                 }
3910*1f882ec4SArmin Le Grand                 else
3911*1f882ec4SArmin Le Grand                 {
3912*1f882ec4SArmin Le Grand                     // add edge
3913*1f882ec4SArmin Le Grand                     aRetval.append(aNewCoordinatePair);
3914*1f882ec4SArmin Le Grand                 }
3915*1f882ec4SArmin Le Grand             }
3916*1f882ec4SArmin Le Grand 
3917*1f882ec4SArmin Le Grand             // #i72807# API import uses old line start/end-equal definition for closed,
3918*1f882ec4SArmin Le Grand             // so we need to correct this to closed state here
3919*1f882ec4SArmin Le Grand             if(bCheckClosed)
3920*1f882ec4SArmin Le Grand             {
3921*1f882ec4SArmin Le Grand                 checkClosed(aRetval);
3922*1f882ec4SArmin Le Grand             }
3923*1f882ec4SArmin Le Grand 
3924*1f882ec4SArmin Le Grand             return aRetval;
3925*1f882ec4SArmin Le Grand         }
3926*1f882ec4SArmin Le Grand 
B2DPolygonToUnoPolygonBezierCoords(const B2DPolygon & rPolygon,com::sun::star::drawing::PointSequence & rPointSequenceRetval,com::sun::star::drawing::FlagSequence & rFlagSequenceRetval)3927*1f882ec4SArmin Le Grand         void B2DPolygonToUnoPolygonBezierCoords(
3928*1f882ec4SArmin Le Grand             const B2DPolygon& rPolygon,
3929*1f882ec4SArmin Le Grand             com::sun::star::drawing::PointSequence& rPointSequenceRetval,
3930*1f882ec4SArmin Le Grand             com::sun::star::drawing::FlagSequence& rFlagSequenceRetval)
3931*1f882ec4SArmin Le Grand         {
3932*1f882ec4SArmin Le Grand             const sal_uInt32 nPointCount(rPolygon.count());
3933*1f882ec4SArmin Le Grand 
3934*1f882ec4SArmin Le Grand             if(nPointCount)
3935*1f882ec4SArmin Le Grand             {
3936*1f882ec4SArmin Le Grand                 const bool bCurve(rPolygon.areControlPointsUsed());
3937*1f882ec4SArmin Le Grand                 const bool bClosed(rPolygon.isClosed());
3938*1f882ec4SArmin Le Grand 
3939*1f882ec4SArmin Le Grand                 if(nPointCount)
3940*1f882ec4SArmin Le Grand                 {
3941*1f882ec4SArmin Le Grand                     if(bCurve)
3942*1f882ec4SArmin Le Grand                     {
3943*1f882ec4SArmin Le Grand                         // calculate target point count
3944*1f882ec4SArmin Le Grand                         const sal_uInt32 nLoopCount(bClosed ? nPointCount : (nPointCount ? nPointCount - 1 : 0));
3945*1f882ec4SArmin Le Grand 
3946*1f882ec4SArmin Le Grand                         if(nLoopCount)
3947*1f882ec4SArmin Le Grand                         {
3948*1f882ec4SArmin Le Grand                             // prepare target data. The real needed number of target points (and flags)
3949*1f882ec4SArmin Le Grand                             // could only be calculated by using two loops, so use dynamic memory
3950*1f882ec4SArmin Le Grand                             std::vector< com::sun::star::awt::Point > aCollectPoints;
3951*1f882ec4SArmin Le Grand                             std::vector< com::sun::star::drawing::PolygonFlags > aCollectFlags;
3952*1f882ec4SArmin Le Grand 
3953*1f882ec4SArmin Le Grand                             // reserve maximum creatable points
3954*1f882ec4SArmin Le Grand                             const sal_uInt32 nMaxTargetCount((nLoopCount * 3) + 1);
3955*1f882ec4SArmin Le Grand                             aCollectPoints.reserve(nMaxTargetCount);
3956*1f882ec4SArmin Le Grand                             aCollectFlags.reserve(nMaxTargetCount);
3957*1f882ec4SArmin Le Grand 
3958*1f882ec4SArmin Le Grand                             // prepare current bezier segment by setting start point
3959*1f882ec4SArmin Le Grand                             B2DCubicBezier aBezierSegment;
3960*1f882ec4SArmin Le Grand                             aBezierSegment.setStartPoint(rPolygon.getB2DPoint(0));
3961*1f882ec4SArmin Le Grand 
3962*1f882ec4SArmin Le Grand                             for(sal_uInt32 a(0); a < nLoopCount; a++)
3963*1f882ec4SArmin Le Grand                             {
3964*1f882ec4SArmin Le Grand                                 // add current point (always) and remember StartPointIndex for evtl. later corrections
3965*1f882ec4SArmin Le Grand                                 const sal_uInt32 nStartPointIndex(aCollectPoints.size());
3966*1f882ec4SArmin Le Grand                                 aCollectPoints.push_back(
3967*1f882ec4SArmin Le Grand                                     com::sun::star::awt::Point(
3968*1f882ec4SArmin Le Grand                                         fround(aBezierSegment.getStartPoint().getX()),
3969*1f882ec4SArmin Le Grand                                         fround(aBezierSegment.getStartPoint().getY())));
3970*1f882ec4SArmin Le Grand                                 aCollectFlags.push_back(com::sun::star::drawing::PolygonFlags_NORMAL);
3971*1f882ec4SArmin Le Grand 
3972*1f882ec4SArmin Le Grand                                 // prepare next segment
3973*1f882ec4SArmin Le Grand                                 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
3974*1f882ec4SArmin Le Grand                                 aBezierSegment.setEndPoint(rPolygon.getB2DPoint(nNextIndex));
3975*1f882ec4SArmin Le Grand                                 aBezierSegment.setControlPointA(rPolygon.getNextControlPoint(a));
3976*1f882ec4SArmin Le Grand                                 aBezierSegment.setControlPointB(rPolygon.getPrevControlPoint(nNextIndex));
3977*1f882ec4SArmin Le Grand 
3978*1f882ec4SArmin Le Grand                                 if(aBezierSegment.isBezier())
3979*1f882ec4SArmin Le Grand                                 {
3980*1f882ec4SArmin Le Grand                                     // if bezier is used, add always two control points due to the old schema
3981*1f882ec4SArmin Le Grand                                     aCollectPoints.push_back(
3982*1f882ec4SArmin Le Grand                                         com::sun::star::awt::Point(
3983*1f882ec4SArmin Le Grand                                             fround(aBezierSegment.getControlPointA().getX()),
3984*1f882ec4SArmin Le Grand                                             fround(aBezierSegment.getControlPointA().getY())));
3985*1f882ec4SArmin Le Grand                                     aCollectFlags.push_back(com::sun::star::drawing::PolygonFlags_CONTROL);
3986*1f882ec4SArmin Le Grand 
3987*1f882ec4SArmin Le Grand                                     aCollectPoints.push_back(
3988*1f882ec4SArmin Le Grand                                         com::sun::star::awt::Point(
3989*1f882ec4SArmin Le Grand                                             fround(aBezierSegment.getControlPointB().getX()),
3990*1f882ec4SArmin Le Grand                                             fround(aBezierSegment.getControlPointB().getY())));
3991*1f882ec4SArmin Le Grand                                     aCollectFlags.push_back(com::sun::star::drawing::PolygonFlags_CONTROL);
3992*1f882ec4SArmin Le Grand                                 }
3993*1f882ec4SArmin Le Grand 
3994*1f882ec4SArmin Le Grand                                 // test continuity with previous control point to set flag value
3995*1f882ec4SArmin Le Grand                                 if(aBezierSegment.getControlPointA() != aBezierSegment.getStartPoint() && (bClosed || a))
3996*1f882ec4SArmin Le Grand                                 {
3997*1f882ec4SArmin Le Grand                                     const B2VectorContinuity eCont(rPolygon.getContinuityInPoint(a));
3998*1f882ec4SArmin Le Grand 
3999*1f882ec4SArmin Le Grand                                     if(CONTINUITY_C1 == eCont)
4000*1f882ec4SArmin Le Grand                                     {
4001*1f882ec4SArmin Le Grand                                         aCollectFlags[nStartPointIndex] = com::sun::star::drawing::PolygonFlags_SMOOTH;
4002*1f882ec4SArmin Le Grand                                     }
4003*1f882ec4SArmin Le Grand                                     else if(CONTINUITY_C2 == eCont)
4004*1f882ec4SArmin Le Grand                                     {
4005*1f882ec4SArmin Le Grand                                         aCollectFlags[nStartPointIndex] = com::sun::star::drawing::PolygonFlags_SYMMETRIC;
4006*1f882ec4SArmin Le Grand                                     }
4007*1f882ec4SArmin Le Grand                                 }
4008*1f882ec4SArmin Le Grand 
4009*1f882ec4SArmin Le Grand                                 // prepare next loop
4010*1f882ec4SArmin Le Grand                                 aBezierSegment.setStartPoint(aBezierSegment.getEndPoint());
4011*1f882ec4SArmin Le Grand                             }
4012*1f882ec4SArmin Le Grand 
4013*1f882ec4SArmin Le Grand                             if(bClosed)
4014*1f882ec4SArmin Le Grand                             {
4015*1f882ec4SArmin Le Grand                                 // add first point again as closing point due to old definition
4016*1f882ec4SArmin Le Grand                                 aCollectPoints.push_back(aCollectPoints[0]);
4017*1f882ec4SArmin Le Grand                                 aCollectFlags.push_back(com::sun::star::drawing::PolygonFlags_NORMAL);
4018*1f882ec4SArmin Le Grand                             }
4019*1f882ec4SArmin Le Grand                             else
4020*1f882ec4SArmin Le Grand                             {
4021*1f882ec4SArmin Le Grand                                 // add last point as closing point
4022*1f882ec4SArmin Le Grand                                 const B2DPoint aClosingPoint(rPolygon.getB2DPoint(nPointCount - 1L));
4023*1f882ec4SArmin Le Grand                                 aCollectPoints.push_back(
4024*1f882ec4SArmin Le Grand                                     com::sun::star::awt::Point(
4025*1f882ec4SArmin Le Grand                                         fround(aClosingPoint.getX()),
4026*1f882ec4SArmin Le Grand                                         fround(aClosingPoint.getY())));
4027*1f882ec4SArmin Le Grand                                 aCollectFlags.push_back(com::sun::star::drawing::PolygonFlags_NORMAL);
4028*1f882ec4SArmin Le Grand                             }
4029*1f882ec4SArmin Le Grand 
4030*1f882ec4SArmin Le Grand                             // copy collected data to target arrays
4031*1f882ec4SArmin Le Grand                             const sal_uInt32 nTargetCount(aCollectPoints.size());
4032*1f882ec4SArmin Le Grand                             OSL_ENSURE(nTargetCount == aCollectFlags.size(), "Unequal Point and Flag count (!)");
4033*1f882ec4SArmin Le Grand 
4034*1f882ec4SArmin Le Grand                             rPointSequenceRetval.realloc((sal_Int32)nTargetCount);
4035*1f882ec4SArmin Le Grand                             rFlagSequenceRetval.realloc((sal_Int32)nTargetCount);
4036*1f882ec4SArmin Le Grand                             com::sun::star::awt::Point* pPointSequence = rPointSequenceRetval.getArray();
4037*1f882ec4SArmin Le Grand                             com::sun::star::drawing::PolygonFlags* pFlagSequence = rFlagSequenceRetval.getArray();
4038*1f882ec4SArmin Le Grand 
4039*1f882ec4SArmin Le Grand                             for(sal_uInt32 a(0); a < nTargetCount; a++)
4040*1f882ec4SArmin Le Grand                             {
4041*1f882ec4SArmin Le Grand                                 *pPointSequence = aCollectPoints[a];
4042*1f882ec4SArmin Le Grand                                 *pFlagSequence = aCollectFlags[a];
4043*1f882ec4SArmin Le Grand                                 pPointSequence++;
4044*1f882ec4SArmin Le Grand                                 pFlagSequence++;
4045*1f882ec4SArmin Le Grand                             }
4046*1f882ec4SArmin Le Grand                         }
4047*1f882ec4SArmin Le Grand                     }
4048*1f882ec4SArmin Le Grand                     else
4049*1f882ec4SArmin Le Grand                     {
4050*1f882ec4SArmin Le Grand                         // straightforward point list creation
4051*1f882ec4SArmin Le Grand                         const sal_uInt32 nTargetCount(nPointCount + (bClosed ? 1 : 0));
4052*1f882ec4SArmin Le Grand 
4053*1f882ec4SArmin Le Grand                         rPointSequenceRetval.realloc((sal_Int32)nTargetCount);
4054*1f882ec4SArmin Le Grand                         rFlagSequenceRetval.realloc((sal_Int32)nTargetCount);
4055*1f882ec4SArmin Le Grand 
4056*1f882ec4SArmin Le Grand                         com::sun::star::awt::Point* pPointSequence = rPointSequenceRetval.getArray();
4057*1f882ec4SArmin Le Grand                         com::sun::star::drawing::PolygonFlags* pFlagSequence = rFlagSequenceRetval.getArray();
4058*1f882ec4SArmin Le Grand 
4059*1f882ec4SArmin Le Grand                         for(sal_uInt32 a(0); a < nPointCount; a++)
4060*1f882ec4SArmin Le Grand                         {
4061*1f882ec4SArmin Le Grand                             const B2DPoint aB2DPoint(rPolygon.getB2DPoint(a));
4062*1f882ec4SArmin Le Grand                             const com::sun::star::awt::Point aAPIPoint(
4063*1f882ec4SArmin Le Grand                                 fround(aB2DPoint.getX()),
4064*1f882ec4SArmin Le Grand                                 fround(aB2DPoint.getY()));
4065*1f882ec4SArmin Le Grand 
4066*1f882ec4SArmin Le Grand                             *pPointSequence = aAPIPoint;
4067*1f882ec4SArmin Le Grand                             *pFlagSequence = com::sun::star::drawing::PolygonFlags_NORMAL;
4068*1f882ec4SArmin Le Grand                             pPointSequence++;
4069*1f882ec4SArmin Le Grand                             pFlagSequence++;
4070*1f882ec4SArmin Le Grand                         }
4071*1f882ec4SArmin Le Grand 
4072*1f882ec4SArmin Le Grand                         if(bClosed)
4073*1f882ec4SArmin Le Grand                         {
4074*1f882ec4SArmin Le Grand                             // add first point as closing point
4075*1f882ec4SArmin Le Grand                             *pPointSequence = *rPointSequenceRetval.getConstArray();
4076*1f882ec4SArmin Le Grand                             *pFlagSequence = com::sun::star::drawing::PolygonFlags_NORMAL;
4077*1f882ec4SArmin Le Grand                         }
4078*1f882ec4SArmin Le Grand                     }
4079*1f882ec4SArmin Le Grand                 }
4080*1f882ec4SArmin Le Grand             }
4081*1f882ec4SArmin Le Grand             else
4082*1f882ec4SArmin Le Grand             {
4083*1f882ec4SArmin Le Grand                 rPointSequenceRetval.realloc(0);
4084*1f882ec4SArmin Le Grand                 rFlagSequenceRetval.realloc(0);
4085*1f882ec4SArmin Le Grand             }
4086*1f882ec4SArmin Le Grand         }
4087*1f882ec4SArmin Le Grand 
4088d8ed516eSArmin Le Grand     } // end of namespace tools
4089cdf0e10cSrcweir } // end of namespace basegfx
4090cdf0e10cSrcweir 
4091cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
4092cdf0e10cSrcweir // eof
4093