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