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 createHalfUnitCircle()
1893         {
1894             static B2DPolygon aUnitHalfCircle;
1895 
1896             if(!aUnitHalfCircle.count())
1897             {
1898                 const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
1899                 const double fScaledKappa(fKappa * (1.0 / STEPSPERQUARTER));
1900                 const B2DHomMatrix aRotateMatrix(createRotateB2DHomMatrix(F_PI2 / STEPSPERQUARTER));
1901                 B2DPoint aPoint(1.0, 0.0);
1902                 B2DPoint aForward(1.0, fScaledKappa);
1903                 B2DPoint aBackward(1.0, -fScaledKappa);
1904 
1905                 aUnitHalfCircle.append(aPoint);
1906 
1907                 for(sal_uInt32 a(0); a < STEPSPERQUARTER * 2; a++)
1908                 {
1909                     aPoint *= aRotateMatrix;
1910                     aBackward *= aRotateMatrix;
1911                     aUnitHalfCircle.appendBezierSegment(aForward, aBackward, aPoint);
1912                     aForward *= aRotateMatrix;
1913                 }
1914             }
1915 
1916             return aUnitHalfCircle;
1917         }
1918 
1919         B2DPolygon createPolygonFromUnitCircle(sal_uInt32 nStartQuadrant)
1920 		{
1921             switch(nStartQuadrant % 4)
1922             {
1923                 case 1 :
1924                 {
1925         			static B2DPolygon aUnitCircleStartQuadrantOne;
1926 
1927                     if(!aUnitCircleStartQuadrantOne.count())
1928                     {
1929     		            ::osl::Mutex m_mutex;
1930                         aUnitCircleStartQuadrantOne = impCreateUnitCircle(1);
1931                     }
1932 
1933                     return aUnitCircleStartQuadrantOne;
1934                 }
1935                 case 2 :
1936                 {
1937         			static B2DPolygon aUnitCircleStartQuadrantTwo;
1938 
1939                     if(!aUnitCircleStartQuadrantTwo.count())
1940                     {
1941     		            ::osl::Mutex m_mutex;
1942                         aUnitCircleStartQuadrantTwo = impCreateUnitCircle(2);
1943                     }
1944 
1945                     return aUnitCircleStartQuadrantTwo;
1946                 }
1947                 case 3 :
1948                 {
1949         			static B2DPolygon aUnitCircleStartQuadrantThree;
1950 
1951                     if(!aUnitCircleStartQuadrantThree.count())
1952                     {
1953     		            ::osl::Mutex m_mutex;
1954                         aUnitCircleStartQuadrantThree = impCreateUnitCircle(3);
1955                     }
1956 
1957                     return aUnitCircleStartQuadrantThree;
1958                 }
1959                 default : // case 0 :
1960                 {
1961         			static B2DPolygon aUnitCircleStartQuadrantZero;
1962 
1963                     if(!aUnitCircleStartQuadrantZero.count())
1964                     {
1965     		            ::osl::Mutex m_mutex;
1966                         aUnitCircleStartQuadrantZero = impCreateUnitCircle(0);
1967                     }
1968 
1969                     return aUnitCircleStartQuadrantZero;
1970                 }
1971             }
1972 		}
1973 
1974         B2DPolygon createPolygonFromEllipse( const B2DPoint& rCenter, double fRadiusX, double fRadiusY )
1975         {
1976 			B2DPolygon aRetval(createPolygonFromUnitCircle());
1977 			const B2DHomMatrix aMatrix(createScaleTranslateB2DHomMatrix(fRadiusX, fRadiusY, rCenter.getX(), rCenter.getY()));
1978 
1979 			aRetval.transform(aMatrix);
1980 
1981             return aRetval;
1982         }
1983 
1984         B2DPolygon createPolygonFromUnitEllipseSegment( double fStart, double fEnd )
1985 		{
1986 	        B2DPolygon aRetval;
1987 
1988 			// truncate fStart, fEnd to a range of [0.0 .. F_2PI[ where F_2PI
1989 			// falls back to 0.0 to ensure a unique definition
1990 			if(fTools::less(fStart, 0.0))
1991 			{
1992 				fStart = 0.0;
1993 			}
1994 
1995 			if(fTools::moreOrEqual(fStart, F_2PI))
1996 			{
1997 				fStart = 0.0;
1998 			}
1999 
2000 			if(fTools::less(fEnd, 0.0))
2001 			{
2002 				fEnd = 0.0;
2003 			}
2004 
2005 			if(fTools::moreOrEqual(fEnd, F_2PI))
2006 			{
2007 				fEnd = 0.0;
2008 			}
2009 
2010 		    if(fTools::equal(fStart, fEnd))
2011             {
2012                 // same start and end angle, add single point
2013                 aRetval.append(B2DPoint(cos(fStart), sin(fStart)));
2014             }
2015             else
2016             {
2017                 const sal_uInt32 nSegments(STEPSPERQUARTER * 4);
2018                 const double fAnglePerSegment(F_PI2 / STEPSPERQUARTER);
2019                 const sal_uInt32 nStartSegment(sal_uInt32(fStart / fAnglePerSegment) % nSegments);
2020                 const sal_uInt32 nEndSegment(sal_uInt32(fEnd / fAnglePerSegment) % nSegments);
2021     	        const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
2022                 const double fScaledKappa(fKappa * (1.0 / STEPSPERQUARTER));
2023 
2024                 B2DPoint aSegStart(cos(fStart), sin(fStart));
2025                 aRetval.append(aSegStart);
2026 
2027                 if(nStartSegment == nEndSegment && fTools::more(fEnd, fStart))
2028                 {
2029                     // start and end in one sector and in the right order, create in one segment
2030                     const B2DPoint aSegEnd(cos(fEnd), sin(fEnd));
2031                     const double fFactor(fScaledKappa * ((fEnd - fStart) / fAnglePerSegment));
2032 
2033                     aRetval.appendBezierSegment(
2034                         aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fFactor),
2035                         aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fFactor),
2036                         aSegEnd);
2037                 }
2038                 else
2039                 {
2040                     double fSegEndRad((nStartSegment + 1) * fAnglePerSegment);
2041                     double fFactor(fScaledKappa * ((fSegEndRad - fStart) / fAnglePerSegment));
2042                     B2DPoint aSegEnd(cos(fSegEndRad), sin(fSegEndRad));
2043 
2044                     aRetval.appendBezierSegment(
2045                         aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fFactor),
2046                         aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fFactor),
2047                         aSegEnd);
2048 
2049                     sal_uInt32 nSegment((nStartSegment + 1) % nSegments);
2050                     aSegStart = aSegEnd;
2051 
2052                     while(nSegment != nEndSegment)
2053                     {
2054                         // No end in this sector, add full sector.
2055                         fSegEndRad = (nSegment + 1) * fAnglePerSegment;
2056                         aSegEnd = B2DPoint(cos(fSegEndRad), sin(fSegEndRad));
2057 
2058 				        aRetval.appendBezierSegment(
2059                             aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fScaledKappa),
2060                             aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fScaledKappa),
2061                             aSegEnd);
2062 
2063                         nSegment = (nSegment + 1) % nSegments;
2064                         aSegStart = aSegEnd;
2065                     }
2066 
2067                     // End in this sector
2068                     const double fSegStartRad(nSegment * fAnglePerSegment);
2069                     fFactor = fScaledKappa * ((fEnd - fSegStartRad) / fAnglePerSegment);
2070                     aSegEnd = B2DPoint(cos(fEnd), sin(fEnd));
2071 
2072                     aRetval.appendBezierSegment(
2073                         aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fFactor),
2074                         aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fFactor),
2075                         aSegEnd);
2076                 }
2077             }
2078 
2079 			// remove double points between segments created by segmented creation
2080 			aRetval.removeDoublePoints();
2081 
2082 			return aRetval;
2083 		}
2084 
2085         B2DPolygon createPolygonFromEllipseSegment( const B2DPoint& rCenter, double fRadiusX, double fRadiusY, double fStart, double fEnd )
2086 		{
2087 	        B2DPolygon aRetval(createPolygonFromUnitEllipseSegment(fStart, fEnd));
2088 			const B2DHomMatrix aMatrix(createScaleTranslateB2DHomMatrix(fRadiusX, fRadiusY, rCenter.getX(), rCenter.getY()));
2089 
2090 			aRetval.transform(aMatrix);
2091 
2092 			return aRetval;
2093 		}
2094 
2095 		bool hasNeutralPoints(const B2DPolygon& rCandidate)
2096 		{
2097 			OSL_ENSURE(!rCandidate.areControlPointsUsed(), "hasNeutralPoints: ATM works not for curves (!)");
2098 			const sal_uInt32 nPointCount(rCandidate.count());
2099 
2100 			if(nPointCount > 2L)
2101 			{
2102 				B2DPoint aPrevPoint(rCandidate.getB2DPoint(nPointCount - 1L));
2103 				B2DPoint aCurrPoint(rCandidate.getB2DPoint(0L));
2104 
2105 				for(sal_uInt32 a(0L); a < nPointCount; a++)
2106 				{
2107 					const B2DPoint aNextPoint(rCandidate.getB2DPoint((a + 1) % nPointCount));
2108 					const B2DVector aPrevVec(aPrevPoint - aCurrPoint);
2109 					const B2DVector aNextVec(aNextPoint - aCurrPoint);
2110 					const B2VectorOrientation aOrientation(getOrientation(aNextVec, aPrevVec));
2111 
2112 					if(ORIENTATION_NEUTRAL == aOrientation)
2113 					{
2114 						// current has neutral orientation
2115 						return true;
2116 					}
2117 					else
2118 					{
2119 						// prepare next
2120 						aPrevPoint = aCurrPoint;
2121 						aCurrPoint = aNextPoint;
2122 					}
2123 				}
2124 			}
2125 
2126 			return false;
2127 		}
2128 
2129 		B2DPolygon removeNeutralPoints(const B2DPolygon& rCandidate)
2130 		{
2131 			if(hasNeutralPoints(rCandidate))
2132 			{
2133 				const sal_uInt32 nPointCount(rCandidate.count());
2134 				B2DPolygon aRetval;
2135 				B2DPoint aPrevPoint(rCandidate.getB2DPoint(nPointCount - 1L));
2136 				B2DPoint aCurrPoint(rCandidate.getB2DPoint(0L));
2137 
2138 				for(sal_uInt32 a(0L); a < nPointCount; a++)
2139 				{
2140 					const B2DPoint aNextPoint(rCandidate.getB2DPoint((a + 1) % nPointCount));
2141 					const B2DVector aPrevVec(aPrevPoint - aCurrPoint);
2142 					const B2DVector aNextVec(aNextPoint - aCurrPoint);
2143 					const B2VectorOrientation aOrientation(getOrientation(aNextVec, aPrevVec));
2144 
2145 					if(ORIENTATION_NEUTRAL == aOrientation)
2146 					{
2147 						// current has neutral orientation, leave it out and prepare next
2148 						aCurrPoint = aNextPoint;
2149 					}
2150 					else
2151 					{
2152 						// add current point
2153 						aRetval.append(aCurrPoint);
2154 
2155 						// prepare next
2156 						aPrevPoint = aCurrPoint;
2157 						aCurrPoint = aNextPoint;
2158 					}
2159 				}
2160 
2161 				while(aRetval.count() && ORIENTATION_NEUTRAL == getOrientationForIndex(aRetval, 0L))
2162 				{
2163 					aRetval.remove(0L);
2164 				}
2165 
2166 				// copy closed state
2167 				aRetval.setClosed(rCandidate.isClosed());
2168 
2169 				return aRetval;
2170 			}
2171 			else
2172 			{
2173 				return rCandidate;
2174 			}
2175 		}
2176 
2177 		bool isConvex(const B2DPolygon& rCandidate)
2178 		{
2179 			OSL_ENSURE(!rCandidate.areControlPointsUsed(), "isConvex: ATM works not for curves (!)");
2180 			const sal_uInt32 nPointCount(rCandidate.count());
2181 
2182 			if(nPointCount > 2L)
2183 			{
2184 				const B2DPoint aPrevPoint(rCandidate.getB2DPoint(nPointCount - 1L));
2185 				B2DPoint aCurrPoint(rCandidate.getB2DPoint(0L));
2186 				B2DVector aCurrVec(aPrevPoint - aCurrPoint);
2187 				B2VectorOrientation aOrientation(ORIENTATION_NEUTRAL);
2188 
2189 				for(sal_uInt32 a(0L); a < nPointCount; a++)
2190 				{
2191 					const B2DPoint aNextPoint(rCandidate.getB2DPoint((a + 1) % nPointCount));
2192 					const B2DVector aNextVec(aNextPoint - aCurrPoint);
2193 					const B2VectorOrientation aCurrentOrientation(getOrientation(aNextVec, aCurrVec));
2194 
2195 					if(ORIENTATION_NEUTRAL == aOrientation)
2196 					{
2197 						// set start value, maybe neutral again
2198 						aOrientation = aCurrentOrientation;
2199 					}
2200 					else
2201 					{
2202 						if(ORIENTATION_NEUTRAL != aCurrentOrientation && aCurrentOrientation != aOrientation)
2203 						{
2204 							// different orientations found, that's it
2205 							return false;
2206 						}
2207 					}
2208 
2209 					// prepare next
2210 					aCurrPoint = aNextPoint;
2211 					aCurrVec = -aNextVec;
2212 				}
2213 			}
2214 
2215 			return true;
2216 		}
2217 
2218 		B2VectorOrientation getOrientationForIndex(const B2DPolygon& rCandidate, sal_uInt32 nIndex)
2219 		{
2220 			OSL_ENSURE(nIndex < rCandidate.count(), "getOrientationForIndex: index out of range (!)");
2221 			const B2DPoint aPrev(rCandidate.getB2DPoint(getIndexOfPredecessor(nIndex, rCandidate)));
2222 			const B2DPoint aCurr(rCandidate.getB2DPoint(nIndex));
2223 			const B2DPoint aNext(rCandidate.getB2DPoint(getIndexOfSuccessor(nIndex, rCandidate)));
2224 			const B2DVector aBack(aPrev - aCurr);
2225 			const B2DVector aForw(aNext - aCurr);
2226 
2227 			return getOrientation(aForw, aBack);
2228 		}
2229 
2230 		bool isPointOnLine(const B2DPoint& rStart, const B2DPoint& rEnd, const B2DPoint& rCandidate, bool bWithPoints)
2231 		{
2232 			if(rCandidate.equal(rStart) || rCandidate.equal(rEnd))
2233 			{
2234 				// candidate is in epsilon around start or end -> inside
2235 				return bWithPoints;
2236 			}
2237 			else if(rStart.equal(rEnd))
2238 			{
2239 				// start and end are equal, but candidate is outside their epsilon -> outside
2240 				return false;
2241 			}
2242 			else
2243 			{
2244 				const B2DVector aEdgeVector(rEnd - rStart);
2245 				const B2DVector aTestVector(rCandidate - rStart);
2246 
2247 				if(areParallel(aEdgeVector, aTestVector))
2248 				{
2249 					const double fZero(0.0);
2250 					const double fOne(1.0);
2251 					const double fParamTestOnCurr(fabs(aEdgeVector.getX()) > fabs(aEdgeVector.getY())
2252 						? aTestVector.getX() / aEdgeVector.getX()
2253 						: aTestVector.getY() / aEdgeVector.getY());
2254 
2255 					if(fTools::more(fParamTestOnCurr, fZero) && fTools::less(fParamTestOnCurr, fOne))
2256 					{
2257 						return true;
2258 					}
2259 				}
2260 
2261 				return false;
2262 			}
2263 		}
2264 
2265 		bool isPointOnPolygon(const B2DPolygon& rCandidate, const B2DPoint& rPoint, bool bWithPoints)
2266 		{
2267 			const B2DPolygon aCandidate(rCandidate.areControlPointsUsed() ? rCandidate.getDefaultAdaptiveSubdivision() : rCandidate);
2268 			const sal_uInt32 nPointCount(aCandidate.count());
2269 
2270 			if(nPointCount > 1L)
2271 			{
2272 				const sal_uInt32 nLoopCount(aCandidate.isClosed() ? nPointCount : nPointCount - 1L);
2273 				B2DPoint aCurrentPoint(aCandidate.getB2DPoint(0L));
2274 
2275 				for(sal_uInt32 a(0L); a < nLoopCount; a++)
2276 				{
2277 					const B2DPoint aNextPoint(aCandidate.getB2DPoint((a + 1L) % nPointCount));
2278 
2279 					if(isPointOnLine(aCurrentPoint, aNextPoint, rPoint, bWithPoints))
2280 					{
2281 						return true;
2282 					}
2283 
2284 					aCurrentPoint = aNextPoint;
2285 				}
2286 			}
2287 			else if(nPointCount && bWithPoints)
2288 			{
2289 				return rPoint.equal(aCandidate.getB2DPoint(0L));
2290 			}
2291 
2292 			return false;
2293 		}
2294 
2295 		bool isPointInTriangle(const B2DPoint& rA, const B2DPoint& rB, const B2DPoint& rC, const B2DPoint& rCandidate, bool bWithBorder)
2296 		{
2297 			if(arePointsOnSameSideOfLine(rA, rB, rC, rCandidate, bWithBorder))
2298 			{
2299 				if(arePointsOnSameSideOfLine(rB, rC, rA, rCandidate, bWithBorder))
2300 				{
2301 					if(arePointsOnSameSideOfLine(rC, rA, rB, rCandidate, bWithBorder))
2302 					{
2303 						return true;
2304 					}
2305 				}
2306 			}
2307 
2308 			return false;
2309 		}
2310 
2311 		bool arePointsOnSameSideOfLine(const B2DPoint& rStart, const B2DPoint& rEnd, const B2DPoint& rCandidateA, const B2DPoint& rCandidateB, bool bWithLine)
2312 		{
2313 			const B2DVector aLineVector(rEnd - rStart);
2314 			const B2DVector aVectorToA(rEnd - rCandidateA);
2315 			const double fCrossA(aLineVector.cross(aVectorToA));
2316 
2317 			if(fTools::equalZero(fCrossA))
2318 			{
2319 				// one point on the line
2320 				return bWithLine;
2321 			}
2322 
2323 			const B2DVector aVectorToB(rEnd - rCandidateB);
2324 			const double fCrossB(aLineVector.cross(aVectorToB));
2325 
2326 			if(fTools::equalZero(fCrossB))
2327 			{
2328 				// one point on the line
2329 				return bWithLine;
2330 			}
2331 
2332 			// return true if they both have the same sign
2333 			return ((fCrossA > 0.0) == (fCrossB > 0.0));
2334 		}
2335 
2336 		void addTriangleFan(const B2DPolygon& rCandidate, B2DPolygon& rTarget)
2337 		{
2338 			const sal_uInt32 nCount(rCandidate.count());
2339 
2340 			if(nCount > 2L)
2341 			{
2342 				const B2DPoint aStart(rCandidate.getB2DPoint(0L));
2343 				B2DPoint aLast(rCandidate.getB2DPoint(1L));
2344 
2345 				for(sal_uInt32 a(2L); a < nCount; a++)
2346 				{
2347 					const B2DPoint aCurrent(rCandidate.getB2DPoint(a));
2348 					rTarget.append(aStart);
2349 					rTarget.append(aLast);
2350 					rTarget.append(aCurrent);
2351 
2352 					// prepare next
2353 					aLast = aCurrent;
2354 				}
2355 			}
2356 		}
2357 
2358         namespace
2359         {
2360             /// return 0 for input of 0, -1 for negative and 1 for positive input
2361             inline int lcl_sgn( const double n )
2362             {
2363                 return n == 0.0 ? 0 : 1 - 2*::rtl::math::isSignBitSet(n);
2364             }
2365         }
2366 
2367         bool isRectangle( const B2DPolygon& rPoly )
2368         {
2369             // polygon must be closed to resemble a rect, and contain
2370             // at least four points.
2371             if( !rPoly.isClosed() ||
2372                 rPoly.count() < 4 ||
2373                 rPoly.areControlPointsUsed() )
2374             {
2375                 return false;
2376             }
2377 
2378             // number of 90 degree turns the polygon has taken
2379             int nNumTurns(0);
2380 
2381             int  nVerticalEdgeType=0;
2382             int  nHorizontalEdgeType=0;
2383             bool bNullVertex(true);
2384             bool bCWPolygon(false);  // when true, polygon is CW
2385                                      // oriented, when false, CCW
2386             bool bOrientationSet(false); // when false, polygon
2387                                          // orientation has not yet
2388                                          // been determined.
2389 
2390             // scan all _edges_ (which involves coming back to point 0
2391             // for the last edge - thus the modulo operation below)
2392             const sal_Int32 nCount( rPoly.count() );
2393             for( sal_Int32 i=0; i<nCount; ++i )
2394             {
2395                 const B2DPoint& rPoint0( rPoly.getB2DPoint(i % nCount) );
2396                 const B2DPoint& rPoint1( rPoly.getB2DPoint((i+1) % nCount) );
2397 
2398                 // is 0 for zero direction vector, 1 for south edge and -1
2399                 // for north edge (standard screen coordinate system)
2400                 int nCurrVerticalEdgeType( lcl_sgn( rPoint1.getY() - rPoint0.getY() ) );
2401 
2402                 // is 0 for zero direction vector, 1 for east edge and -1
2403                 // for west edge (standard screen coordinate system)
2404                 int nCurrHorizontalEdgeType( lcl_sgn(rPoint1.getX() - rPoint0.getX()) );
2405 
2406                 if( nCurrVerticalEdgeType && nCurrHorizontalEdgeType )
2407                     return false; // oblique edge - for sure no rect
2408 
2409                 const bool bCurrNullVertex( !nCurrVerticalEdgeType && !nCurrHorizontalEdgeType );
2410 
2411                 // current vertex is equal to previous - just skip,
2412                 // until we have a real edge
2413                 if( bCurrNullVertex )
2414                     continue;
2415 
2416                 // if previous edge has two identical points, because
2417                 // no previous edge direction was available, simply
2418                 // take this first non-null edge as the start
2419                 // direction. That's what will happen here, if
2420                 // bNullVertex is false
2421                 if( !bNullVertex )
2422                 {
2423                     // 2D cross product - is 1 for CW and -1 for CCW turns
2424                     const int nCrossProduct( nHorizontalEdgeType*nCurrVerticalEdgeType -
2425                                              nVerticalEdgeType*nCurrHorizontalEdgeType );
2426 
2427                     if( !nCrossProduct )
2428                         continue; // no change in orientation -
2429                                   // collinear edges - just go on
2430 
2431                     // if polygon orientation is not set, we'll
2432                     // determine it now
2433                     if( !bOrientationSet )
2434                     {
2435                         bCWPolygon = nCrossProduct == 1;
2436                         bOrientationSet = true;
2437                     }
2438                     else
2439                     {
2440                         // if current turn orientation is not equal
2441                         // initial orientation, this is not a
2442                         // rectangle (as rectangles have consistent
2443                         // orientation).
2444                         if( (nCrossProduct == 1) != bCWPolygon )
2445                             return false;
2446                     }
2447 
2448                     ++nNumTurns;
2449 
2450                     // More than four 90 degree turns are an
2451                     // indication that this must not be a rectangle.
2452                     if( nNumTurns > 4 )
2453                         return false;
2454                 }
2455 
2456                 // store current state for the next turn
2457                 nVerticalEdgeType	= nCurrVerticalEdgeType;
2458                 nHorizontalEdgeType = nCurrHorizontalEdgeType;
2459                 bNullVertex		    = false; // won't reach this line,
2460                                              // if bCurrNullVertex is
2461                                              // true - see above
2462             }
2463 
2464             return true;
2465         }
2466 
2467 		B3DPolygon createB3DPolygonFromB2DPolygon(const B2DPolygon& rCandidate, double fZCoordinate)
2468 		{
2469 			if(rCandidate.areControlPointsUsed())
2470 			{
2471 				// call myself recursively with subdivided input
2472 				const B2DPolygon aCandidate(adaptiveSubdivideByAngle(rCandidate));
2473 				return createB3DPolygonFromB2DPolygon(aCandidate, fZCoordinate);
2474 			}
2475 			else
2476 			{
2477 				B3DPolygon aRetval;
2478 
2479 				for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
2480 				{
2481 					B2DPoint aPoint(rCandidate.getB2DPoint(a));
2482 					aRetval.append(B3DPoint(aPoint.getX(), aPoint.getY(), fZCoordinate));
2483 				}
2484 
2485 				// copy closed state
2486 				aRetval.setClosed(rCandidate.isClosed());
2487 
2488 				return aRetval;
2489 			}
2490 		}
2491 
2492 		B2DPolygon createB2DPolygonFromB3DPolygon(const B3DPolygon& rCandidate, const B3DHomMatrix& rMat)
2493 		{
2494 			B2DPolygon aRetval;
2495 			const sal_uInt32 nCount(rCandidate.count());
2496 			const bool bIsIdentity(rMat.isIdentity());
2497 
2498 			for(sal_uInt32 a(0L); a < nCount; a++)
2499 			{
2500 				B3DPoint aCandidate(rCandidate.getB3DPoint(a));
2501 
2502 				if(!bIsIdentity)
2503 				{
2504 					aCandidate *= rMat;
2505 				}
2506 
2507 				aRetval.append(B2DPoint(aCandidate.getX(), aCandidate.getY()));
2508 			}
2509 
2510 			// copy closed state
2511 			aRetval.setClosed(rCandidate.isClosed());
2512 
2513 			return aRetval;
2514 		}
2515 
2516 		double getDistancePointToEndlessRay(const B2DPoint& rPointA, const B2DPoint& rPointB, const B2DPoint& rTestPoint, double& rCut)
2517 		{
2518 			if(rPointA.equal(rPointB))
2519 			{
2520 				rCut = 0.0;
2521 				const B2DVector aVector(rTestPoint - rPointA);
2522 				return aVector.getLength();
2523 			}
2524 			else
2525 			{
2526 				// get the relative cut value on line vector (Vector1) for cut with perpendicular through TestPoint
2527 				const B2DVector aVector1(rPointB - rPointA);
2528 				const B2DVector aVector2(rTestPoint - rPointA);
2529 				const double fDividend((aVector2.getX() * aVector1.getX()) + (aVector2.getY() * aVector1.getY()));
2530 				const double fDivisor((aVector1.getX() * aVector1.getX()) + (aVector1.getY() * aVector1.getY()));
2531 
2532                 rCut = fDividend / fDivisor;
2533 
2534 				const B2DPoint aCutPoint(rPointA + rCut * aVector1);
2535 				const B2DVector aVector(rTestPoint - aCutPoint);
2536 				return aVector.getLength();
2537 			}
2538 		}
2539 
2540 		double getSmallestDistancePointToEdge(const B2DPoint& rPointA, const B2DPoint& rPointB, const B2DPoint& rTestPoint, double& rCut)
2541 		{
2542 			if(rPointA.equal(rPointB))
2543 			{
2544 				rCut = 0.0;
2545 				const B2DVector aVector(rTestPoint - rPointA);
2546 				return aVector.getLength();
2547 			}
2548 			else
2549 			{
2550 				// get the relative cut value on line vector (Vector1) for cut with perpendicular through TestPoint
2551 				const B2DVector aVector1(rPointB - rPointA);
2552 				const B2DVector aVector2(rTestPoint - rPointA);
2553 				const double fDividend((aVector2.getX() * aVector1.getX()) + (aVector2.getY() * aVector1.getY()));
2554 				const double fDivisor((aVector1.getX() * aVector1.getX()) + (aVector1.getY() * aVector1.getY()));
2555 				const double fCut(fDividend / fDivisor);
2556 
2557 				if(fCut < 0.0)
2558 				{
2559 					// not in line range, get distance to PointA
2560 					rCut = 0.0;
2561 					return aVector2.getLength();
2562 				}
2563 				else if(fCut > 1.0)
2564 				{
2565 					// not in line range, get distance to PointB
2566 					rCut = 1.0;
2567 					const B2DVector aVector(rTestPoint - rPointB);
2568 					return aVector.getLength();
2569 				}
2570 				else
2571 				{
2572 					// in line range
2573 					const B2DPoint aCutPoint(rPointA + fCut * aVector1);
2574 					const B2DVector aVector(rTestPoint - aCutPoint);
2575 					rCut = fCut;
2576 					return aVector.getLength();
2577 				}
2578 			}
2579 		}
2580 
2581 		double getSmallestDistancePointToPolygon(const B2DPolygon& rCandidate, const B2DPoint& rTestPoint, sal_uInt32& rEdgeIndex, double& rCut)
2582 		{
2583 			double fRetval(DBL_MAX);
2584 			const sal_uInt32 nPointCount(rCandidate.count());
2585 
2586 			if(nPointCount > 1L)
2587 			{
2588 				const double fZero(0.0);
2589 				const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
2590 				B2DCubicBezier aBezier;
2591 				aBezier.setStartPoint(rCandidate.getB2DPoint(0));
2592 
2593 				for(sal_uInt32 a(0L); a < nEdgeCount; a++)
2594 				{
2595 					const sal_uInt32 nNextIndex((a + 1) % nPointCount);
2596 					aBezier.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
2597 					double fEdgeDist;
2598 					double fNewCut;
2599 					bool bEdgeIsCurve(false);
2600 
2601 					if(rCandidate.areControlPointsUsed())
2602 					{
2603 						aBezier.setControlPointA(rCandidate.getNextControlPoint(a));
2604 						aBezier.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
2605 						aBezier.testAndSolveTrivialBezier();
2606 						bEdgeIsCurve = aBezier.isBezier();
2607 					}
2608 
2609 					if(bEdgeIsCurve)
2610 					{
2611 						fEdgeDist = aBezier.getSmallestDistancePointToBezierSegment(rTestPoint, fNewCut);
2612 					}
2613 					else
2614 					{
2615 						fEdgeDist = getSmallestDistancePointToEdge(aBezier.getStartPoint(), aBezier.getEndPoint(), rTestPoint, fNewCut);
2616 					}
2617 
2618 					if(DBL_MAX == fRetval || fEdgeDist < fRetval)
2619 					{
2620 						fRetval = fEdgeDist;
2621 						rEdgeIndex = a;
2622 						rCut = fNewCut;
2623 
2624 						if(fTools::equal(fRetval, fZero))
2625 						{
2626 							// already found zero distance, cannot get better. Ensure numerical zero value and end loop.
2627 							fRetval = 0.0;
2628 							break;
2629 						}
2630 					}
2631 
2632 					// prepare next step
2633 					aBezier.setStartPoint(aBezier.getEndPoint());
2634 				}
2635 
2636 				if(1.0 == rCut)
2637 				{
2638 					// correct rEdgeIndex when not last point
2639 					if(rCandidate.isClosed())
2640 					{
2641 						rEdgeIndex = getIndexOfSuccessor(rEdgeIndex, rCandidate);
2642 						rCut = 0.0;
2643 					}
2644 					else
2645 					{
2646 						if(rEdgeIndex != nEdgeCount - 1L)
2647 						{
2648 							rEdgeIndex++;
2649 							rCut = 0.0;
2650 						}
2651 					}
2652 				}
2653 			}
2654 
2655 			return fRetval;
2656 		}
2657 
2658 		B2DPoint distort(const B2DPoint& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight)
2659 		{
2660 			if(fTools::equalZero(rOriginal.getWidth()) || fTools::equalZero(rOriginal.getHeight()))
2661 			{
2662 				return rCandidate;
2663 			}
2664 			else
2665 			{
2666 				const double fRelativeX((rCandidate.getX() - rOriginal.getMinX()) / rOriginal.getWidth());
2667 				const double fRelativeY((rCandidate.getY() - rOriginal.getMinY()) / rOriginal.getHeight());
2668 				const double fOneMinusRelativeX(1.0 - fRelativeX);
2669 				const double fOneMinusRelativeY(1.0 - fRelativeY);
2670 				const double fNewX((fOneMinusRelativeY) * ((fOneMinusRelativeX) * rTopLeft.getX() + fRelativeX * rTopRight.getX()) +
2671 					fRelativeY * ((fOneMinusRelativeX) * rBottomLeft.getX() + fRelativeX * rBottomRight.getX()));
2672 				const double fNewY((fOneMinusRelativeX) * ((fOneMinusRelativeY) * rTopLeft.getY() + fRelativeY * rBottomLeft.getY()) +
2673 					fRelativeX * ((fOneMinusRelativeY) * rTopRight.getY() + fRelativeY * rBottomRight.getY()));
2674 
2675 				return B2DPoint(fNewX, fNewY);
2676 			}
2677 		}
2678 
2679 		B2DPolygon distort(const B2DPolygon& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight)
2680 		{
2681 			const sal_uInt32 nPointCount(rCandidate.count());
2682 
2683 			if(nPointCount && 0.0 != rOriginal.getWidth() && 0.0 != rOriginal.getHeight())
2684 			{
2685 				B2DPolygon aRetval;
2686 
2687 				for(sal_uInt32 a(0L); a < nPointCount; a++)
2688 				{
2689 					aRetval.append(distort(rCandidate.getB2DPoint(a), rOriginal, rTopLeft, rTopRight, rBottomLeft, rBottomRight));
2690 
2691 					if(rCandidate.areControlPointsUsed())
2692 					{
2693 						if(!rCandidate.getPrevControlPoint(a).equalZero())
2694 						{
2695 							aRetval.setPrevControlPoint(a, distort(rCandidate.getPrevControlPoint(a), rOriginal, rTopLeft, rTopRight, rBottomLeft, rBottomRight));
2696 						}
2697 
2698 						if(!rCandidate.getNextControlPoint(a).equalZero())
2699 						{
2700 							aRetval.setNextControlPoint(a, distort(rCandidate.getNextControlPoint(a), rOriginal, rTopLeft, rTopRight, rBottomLeft, rBottomRight));
2701 						}
2702 					}
2703 				}
2704 
2705 				aRetval.setClosed(rCandidate.isClosed());
2706 				return aRetval;
2707 			}
2708 			else
2709 			{
2710 				return rCandidate;
2711 			}
2712 		}
2713 
2714 		B2DPolygon rotateAroundPoint(const B2DPolygon& rCandidate, const B2DPoint& rCenter, double fAngle)
2715 		{
2716 			const sal_uInt32 nPointCount(rCandidate.count());
2717 			B2DPolygon aRetval(rCandidate);
2718 
2719 			if(nPointCount)
2720 			{
2721                 const B2DHomMatrix aMatrix(basegfx::tools::createRotateAroundPoint(rCenter, fAngle));
2722 
2723                 aRetval.transform(aMatrix);
2724 			}
2725 
2726 			return aRetval;
2727 		}
2728 
2729 		B2DPolygon expandToCurve(const B2DPolygon& rCandidate)
2730 		{
2731 			B2DPolygon aRetval(rCandidate);
2732 
2733 			for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
2734 			{
2735 				expandToCurveInPoint(aRetval, a);
2736 			}
2737 
2738 			return aRetval;
2739 		}
2740 
2741 		bool expandToCurveInPoint(B2DPolygon& rCandidate, sal_uInt32 nIndex)
2742 		{
2743 			OSL_ENSURE(nIndex < rCandidate.count(), "expandToCurveInPoint: Access to polygon out of range (!)");
2744 			bool bRetval(false);
2745 			const sal_uInt32 nPointCount(rCandidate.count());
2746 
2747 			if(nPointCount)
2748 			{
2749 				// predecessor
2750 				if(!rCandidate.isPrevControlPointUsed(nIndex))
2751 				{
2752 					if(!rCandidate.isClosed() && 0 == nIndex)
2753 					{
2754 						// do not create previous vector for start point of open polygon
2755 					}
2756 					else
2757 					{
2758 						const sal_uInt32 nPrevIndex((nIndex + (nPointCount - 1)) % nPointCount);
2759 						rCandidate.setPrevControlPoint(nIndex, interpolate(rCandidate.getB2DPoint(nIndex), rCandidate.getB2DPoint(nPrevIndex), 1.0 / 3.0));
2760 						bRetval = true;
2761 					}
2762 				}
2763 
2764 				// successor
2765 				if(!rCandidate.isNextControlPointUsed(nIndex))
2766 				{
2767 					if(!rCandidate.isClosed() && nIndex + 1 == nPointCount)
2768 					{
2769 						// do not create next vector for end point of open polygon
2770 					}
2771 					else
2772 					{
2773 						const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
2774 						rCandidate.setNextControlPoint(nIndex, interpolate(rCandidate.getB2DPoint(nIndex), rCandidate.getB2DPoint(nNextIndex), 1.0 / 3.0));
2775 						bRetval = true;
2776 					}
2777 				}
2778 			}
2779 
2780 			return bRetval;
2781 		}
2782 
2783 		B2DPolygon setContinuity(const B2DPolygon& rCandidate, B2VectorContinuity eContinuity)
2784 		{
2785 			B2DPolygon aRetval(rCandidate);
2786 
2787 			for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
2788 			{
2789 				setContinuityInPoint(aRetval, a, eContinuity);
2790 			}
2791 
2792 			return aRetval;
2793 		}
2794 
2795 		bool setContinuityInPoint(B2DPolygon& rCandidate, sal_uInt32 nIndex, B2VectorContinuity eContinuity)
2796 		{
2797 			OSL_ENSURE(nIndex < rCandidate.count(), "setContinuityInPoint: Access to polygon out of range (!)");
2798 			bool bRetval(false);
2799 			const sal_uInt32 nPointCount(rCandidate.count());
2800 
2801 			if(nPointCount)
2802 			{
2803 				const B2DPoint aCurrentPoint(rCandidate.getB2DPoint(nIndex));
2804 
2805 				switch(eContinuity)
2806 				{
2807 					case CONTINUITY_NONE :
2808 					{
2809 						if(rCandidate.isPrevControlPointUsed(nIndex))
2810 						{
2811 							if(!rCandidate.isClosed() && 0 == nIndex)
2812 							{
2813 								// remove existing previous vector for start point of open polygon
2814 								rCandidate.resetPrevControlPoint(nIndex);
2815 							}
2816 							else
2817 							{
2818 								const sal_uInt32 nPrevIndex((nIndex + (nPointCount - 1)) % nPointCount);
2819 								rCandidate.setPrevControlPoint(nIndex, interpolate(aCurrentPoint, rCandidate.getB2DPoint(nPrevIndex), 1.0 / 3.0));
2820 							}
2821 
2822 							bRetval = true;
2823 						}
2824 
2825 						if(rCandidate.isNextControlPointUsed(nIndex))
2826 						{
2827 							if(!rCandidate.isClosed() && nIndex == nPointCount + 1)
2828 							{
2829 								// remove next vector for end point of open polygon
2830 								rCandidate.resetNextControlPoint(nIndex);
2831 							}
2832 							else
2833 							{
2834 								const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
2835 								rCandidate.setNextControlPoint(nIndex, interpolate(aCurrentPoint, rCandidate.getB2DPoint(nNextIndex), 1.0 / 3.0));
2836 							}
2837 
2838 							bRetval = true;
2839 						}
2840 
2841 						break;
2842 					}
2843 					case CONTINUITY_C1 :
2844 					{
2845 						if(rCandidate.isPrevControlPointUsed(nIndex) && rCandidate.isNextControlPointUsed(nIndex))
2846 						{
2847 							// lengths both exist since both are used
2848 							B2DVector aVectorPrev(rCandidate.getPrevControlPoint(nIndex) - aCurrentPoint);
2849 							B2DVector aVectorNext(rCandidate.getNextControlPoint(nIndex) - aCurrentPoint);
2850 							const double fLenPrev(aVectorPrev.getLength());
2851 							const double fLenNext(aVectorNext.getLength());
2852 							aVectorPrev.normalize();
2853 							aVectorNext.normalize();
2854 							const B2VectorOrientation aOrientation(getOrientation(aVectorPrev, aVectorNext));
2855 
2856 							if(ORIENTATION_NEUTRAL == aOrientation && aVectorPrev.scalar(aVectorNext) < 0.0)
2857 							{
2858 								// parallel and opposite direction; check length
2859 								if(fTools::equal(fLenPrev, fLenNext))
2860 								{
2861 									// this would be even C2, but we want C1. Use the lengths of the corresponding edges.
2862 									const sal_uInt32 nPrevIndex((nIndex + (nPointCount - 1)) % nPointCount);
2863 									const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
2864 									const double fLenPrevEdge(B2DVector(rCandidate.getB2DPoint(nPrevIndex) - aCurrentPoint).getLength() * (1.0 / 3.0));
2865 									const double fLenNextEdge(B2DVector(rCandidate.getB2DPoint(nNextIndex) - aCurrentPoint).getLength() * (1.0 / 3.0));
2866 
2867 									rCandidate.setControlPoints(nIndex,
2868 										aCurrentPoint + (aVectorPrev * fLenPrevEdge),
2869 										aCurrentPoint + (aVectorNext * fLenNextEdge));
2870 									bRetval = true;
2871 								}
2872 							}
2873 							else
2874 							{
2875 								// not parallel or same direction, set vectors and length
2876 								const B2DVector aNormalizedPerpendicular(getNormalizedPerpendicular(aVectorPrev + aVectorNext));
2877 
2878 								if(ORIENTATION_POSITIVE == aOrientation)
2879 								{
2880 									rCandidate.setControlPoints(nIndex,
2881 										aCurrentPoint - (aNormalizedPerpendicular * fLenPrev),
2882 										aCurrentPoint + (aNormalizedPerpendicular * fLenNext));
2883 								}
2884 								else
2885 								{
2886 									rCandidate.setControlPoints(nIndex,
2887 										aCurrentPoint + (aNormalizedPerpendicular * fLenPrev),
2888 										aCurrentPoint - (aNormalizedPerpendicular * fLenNext));
2889 								}
2890 
2891 								bRetval = true;
2892 							}
2893 						}
2894 						break;
2895 					}
2896 					case CONTINUITY_C2 :
2897 					{
2898 						if(rCandidate.isPrevControlPointUsed(nIndex) && rCandidate.isNextControlPointUsed(nIndex))
2899 						{
2900 							// lengths both exist since both are used
2901 							B2DVector aVectorPrev(rCandidate.getPrevControlPoint(nIndex) - aCurrentPoint);
2902 							B2DVector aVectorNext(rCandidate.getNextControlPoint(nIndex) - aCurrentPoint);
2903 							const double fCommonLength((aVectorPrev.getLength() + aVectorNext.getLength()) / 2.0);
2904 							aVectorPrev.normalize();
2905 							aVectorNext.normalize();
2906 							const B2VectorOrientation aOrientation(getOrientation(aVectorPrev, aVectorNext));
2907 
2908 							if(ORIENTATION_NEUTRAL == aOrientation && aVectorPrev.scalar(aVectorNext) < 0.0)
2909 							{
2910 								// parallel and opposite direction; set length. Use one direction for better numerical correctness
2911 								const B2DVector aScaledDirection(aVectorPrev * fCommonLength);
2912 
2913 								rCandidate.setControlPoints(nIndex,
2914 									aCurrentPoint + aScaledDirection,
2915 									aCurrentPoint - aScaledDirection);
2916 							}
2917 							else
2918 							{
2919 								// not parallel or same direction, set vectors and length
2920 								const B2DVector aNormalizedPerpendicular(getNormalizedPerpendicular(aVectorPrev + aVectorNext));
2921 								const B2DVector aPerpendicular(aNormalizedPerpendicular * fCommonLength);
2922 
2923 								if(ORIENTATION_POSITIVE == aOrientation)
2924 								{
2925 									rCandidate.setControlPoints(nIndex,
2926 										aCurrentPoint - aPerpendicular,
2927 										aCurrentPoint + aPerpendicular);
2928 								}
2929 								else
2930 								{
2931 									rCandidate.setControlPoints(nIndex,
2932 										aCurrentPoint + aPerpendicular,
2933 										aCurrentPoint - aPerpendicular);
2934 								}
2935 							}
2936 
2937 							bRetval = true;
2938 						}
2939 						break;
2940 					}
2941 				}
2942 			}
2943 
2944 			return bRetval;
2945 		}
2946 
2947 		B2DPolygon growInNormalDirection(const B2DPolygon& rCandidate, double fValue)
2948 		{
2949 			if(0.0 != fValue)
2950 			{
2951 				if(rCandidate.areControlPointsUsed())
2952 				{
2953 					// call myself recursively with subdivided input
2954 					const B2DPolygon aCandidate(adaptiveSubdivideByAngle(rCandidate));
2955 					return growInNormalDirection(aCandidate, fValue);
2956 				}
2957 				else
2958 				{
2959 					B2DPolygon aRetval;
2960 					const sal_uInt32 nPointCount(rCandidate.count());
2961 
2962 					if(nPointCount)
2963 					{
2964 						B2DPoint aPrev(rCandidate.getB2DPoint(nPointCount - 1L));
2965 						B2DPoint aCurrent(rCandidate.getB2DPoint(0L));
2966 
2967 						for(sal_uInt32 a(0L); a < nPointCount; a++)
2968 						{
2969 							const B2DPoint aNext(rCandidate.getB2DPoint(a + 1L == nPointCount ? 0L : a + 1L));
2970 							const B2DVector aBack(aPrev - aCurrent);
2971 							const B2DVector aForw(aNext - aCurrent);
2972 							const B2DVector aPerpBack(getNormalizedPerpendicular(aBack));
2973 							const B2DVector aPerpForw(getNormalizedPerpendicular(aForw));
2974 							B2DVector aDirection(aPerpBack - aPerpForw);
2975 							aDirection.normalize();
2976 							aDirection *= fValue;
2977 							aRetval.append(aCurrent + aDirection);
2978 
2979 							// prepare next step
2980 							aPrev = aCurrent;
2981 							aCurrent = aNext;
2982 						}
2983 					}
2984 
2985 					// copy closed state
2986 					aRetval.setClosed(rCandidate.isClosed());
2987 
2988 					return aRetval;
2989 				}
2990 			}
2991 			else
2992 			{
2993 				return rCandidate;
2994 			}
2995 		}
2996 
2997 		B2DPolygon reSegmentPolygon(const B2DPolygon& rCandidate, sal_uInt32 nSegments)
2998 		{
2999 			B2DPolygon aRetval;
3000 			const sal_uInt32 nPointCount(rCandidate.count());
3001 
3002 			if(nPointCount && nSegments)
3003 			{
3004 				// get current segment count
3005 				const sal_uInt32 nSegmentCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
3006 
3007 				if(nSegmentCount == nSegments)
3008 				{
3009 					aRetval = rCandidate;
3010 				}
3011 				else
3012 				{
3013 					const double fLength(getLength(rCandidate));
3014 					const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nSegments : nSegments + 1L);
3015 
3016 					for(sal_uInt32 a(0L); a < nLoopCount; a++)
3017 					{
3018 						const double fRelativePos((double)a / (double)nSegments); // 0.0 .. 1.0
3019 						const B2DPoint aNewPoint(getPositionRelative(rCandidate, fRelativePos, fLength));
3020 						aRetval.append(aNewPoint);
3021 					}
3022 
3023 					// copy closed flag
3024 					aRetval.setClosed(rCandidate.isClosed());
3025 				}
3026 			}
3027 
3028 			return aRetval;
3029 		}
3030 
3031 		B2DPolygon reSegmentPolygonEdges(const B2DPolygon& rCandidate, sal_uInt32 nSubEdges, bool bHandleCurvedEdges, bool bHandleStraightEdges)
3032 		{
3033 			const sal_uInt32 nPointCount(rCandidate.count());
3034 
3035             if(nPointCount < 2 || nSubEdges < 2 || (!bHandleCurvedEdges && !bHandleStraightEdges))
3036             {
3037                 // nothing to do:
3038                 // - less than two points -> no edge at all
3039                 // - less than two nSubEdges -> no resegment necessary
3040                 // - neither bHandleCurvedEdges nor bHandleStraightEdges -> nothing to do
3041                 return rCandidate;
3042             }
3043             else
3044             {
3045     			B2DPolygon aRetval;
3046                 const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
3047                 B2DCubicBezier aCurrentEdge;
3048 
3049                 // prepare first edge and add start point to target
3050                 aCurrentEdge.setStartPoint(rCandidate.getB2DPoint(0));
3051                 aRetval.append(aCurrentEdge.getStartPoint());
3052 
3053                 for(sal_uInt32 a(0); a < nEdgeCount; a++)
3054                 {
3055                     // fill edge
3056                     const sal_uInt32 nNextIndex((a + 1) % nPointCount);
3057                     aCurrentEdge.setControlPointA(rCandidate.getNextControlPoint(a));
3058                     aCurrentEdge.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
3059                     aCurrentEdge.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
3060 
3061                     if(aCurrentEdge.isBezier())
3062                     {
3063                         if(bHandleCurvedEdges)
3064                         {
3065                             for(sal_uInt32 b(nSubEdges); b > 1; b--)
3066                             {
3067                                 const double fSplitPoint(1.0 / b);
3068                                 B2DCubicBezier aLeftPart;
3069 
3070                                 aCurrentEdge.split(fSplitPoint, &aLeftPart, &aCurrentEdge);
3071                                 aRetval.appendBezierSegment(aLeftPart.getControlPointA(), aLeftPart.getControlPointB(), aLeftPart.getEndPoint());
3072                             }
3073                         }
3074 
3075                         // copy remaining segment to target
3076                         aRetval.appendBezierSegment(aCurrentEdge.getControlPointA(), aCurrentEdge.getControlPointB(), aCurrentEdge.getEndPoint());
3077                     }
3078                     else
3079                     {
3080                         if(bHandleStraightEdges)
3081                         {
3082                             for(sal_uInt32 b(nSubEdges); b > 1; b--)
3083                             {
3084                                 const double fSplitPoint(1.0 / b);
3085                                 const B2DPoint aSplitPoint(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fSplitPoint));
3086 
3087                                 aRetval.append(aSplitPoint);
3088                                 aCurrentEdge.setStartPoint(aSplitPoint);
3089                             }
3090                         }
3091 
3092                         // copy remaining segment to target
3093                         aRetval.append(aCurrentEdge.getEndPoint());
3094                     }
3095 
3096                     // prepare next step
3097                     aCurrentEdge.setStartPoint(aCurrentEdge.getEndPoint());
3098                 }
3099 
3100                 // copy closed flag and return
3101                 aRetval.setClosed(rCandidate.isClosed());
3102                 return aRetval;
3103             }
3104         }
3105 
3106 		B2DPolygon interpolate(const B2DPolygon& rOld1, const B2DPolygon& rOld2, double t)
3107 		{
3108 			OSL_ENSURE(rOld1.count() == rOld2.count(), "B2DPolygon interpolate: Different geometry (!)");
3109 
3110 			if(fTools::lessOrEqual(t, 0.0) || rOld1 == rOld2)
3111 			{
3112 				return rOld1;
3113 			}
3114 			else if(fTools::moreOrEqual(t, 1.0))
3115 			{
3116 				return rOld2;
3117 			}
3118 			else
3119 			{
3120 				B2DPolygon aRetval;
3121 				const bool bInterpolateVectors(rOld1.areControlPointsUsed() || rOld2.areControlPointsUsed());
3122 				aRetval.setClosed(rOld1.isClosed() && rOld2.isClosed());
3123 
3124 				for(sal_uInt32 a(0L); a < rOld1.count(); a++)
3125 				{
3126 					aRetval.append(interpolate(rOld1.getB2DPoint(a), rOld2.getB2DPoint(a), t));
3127 
3128 					if(bInterpolateVectors)
3129 					{
3130 						aRetval.setPrevControlPoint(a, interpolate(rOld1.getPrevControlPoint(a), rOld2.getPrevControlPoint(a), t));
3131 						aRetval.setNextControlPoint(a, interpolate(rOld1.getNextControlPoint(a), rOld2.getNextControlPoint(a), t));
3132 					}
3133 				}
3134 
3135 				return aRetval;
3136 			}
3137 		}
3138 
3139 		bool isPolyPolygonEqualRectangle( const B2DPolyPolygon& rPolyPoly,
3140 										  const B2DRange&	   rRect )
3141         {
3142             // exclude some cheap cases first
3143             if( rPolyPoly.count() != 1 )
3144                 return false;
3145 
3146             // fill array with rectangle vertices
3147             const B2DPoint aPoints[] =
3148               {
3149 				  B2DPoint(rRect.getMinX(),rRect.getMinY()),
3150 				  B2DPoint(rRect.getMaxX(),rRect.getMinY()),
3151 				  B2DPoint(rRect.getMaxX(),rRect.getMaxY()),
3152 				  B2DPoint(rRect.getMinX(),rRect.getMaxY())
3153               };
3154 
3155 			const B2DPolygon& rPoly( rPolyPoly.getB2DPolygon(0) );
3156 			const sal_uInt32 nCount( rPoly.count() );
3157 			const double epsilon = ::std::numeric_limits<double>::epsilon();
3158 
3159 			for(unsigned int j=0; j<4; ++j)
3160 			{
3161 				const B2DPoint &p1 = aPoints[j];
3162 				const B2DPoint &p2 = aPoints[(j+1)%4];
3163 				bool bPointOnBoundary = false;
3164 				for( sal_uInt32 i=0; i<nCount; ++i )
3165 				{
3166 					const B2DPoint p(rPoly.getB2DPoint(i));
3167 
3168 					//	   1 | x0 y0 1 |
3169 					// A = - | x1 y1 1 |
3170 					//	   2 | x2 y2 1 |
3171 					double fDoubleArea = p2.getX()*p.getY() -
3172 										 p2.getY()*p.getX() -
3173 										 p1.getX()*p.getY() +
3174 										 p1.getY()*p.getX() +
3175 										 p1.getX()*p2.getY() -
3176 										 p1.getY()*p2.getX();
3177 
3178 					if(fDoubleArea < epsilon)
3179 					{
3180 						bPointOnBoundary=true;
3181 						break;
3182 					}
3183 				}
3184 				if(!(bPointOnBoundary))
3185 					return false;
3186 			}
3187 
3188 			return true;
3189         }
3190 
3191 
3192 		// create simplified version of the original polygon by
3193 		// replacing segments with spikes/loops and self intersections
3194 		// by several trivial sub-segments
3195 		B2DPolygon createSimplifiedPolygon( const B2DPolygon& rCandidate )
3196 		{
3197 			const sal_uInt32 nCount(rCandidate.count());
3198 
3199 			if(nCount && rCandidate.areControlPointsUsed())
3200 			{
3201 				const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nCount : nCount - 1);
3202 				B2DPolygon aRetval;
3203 				B2DCubicBezier aSegment;
3204 
3205 				aSegment.setStartPoint(rCandidate.getB2DPoint(0));
3206 				aRetval.append(aSegment.getStartPoint());
3207 
3208 				for(sal_uInt32 a(0); a < nEdgeCount; a++)
3209 				{
3210 					// fill edge
3211 					const sal_uInt32 nNextIndex((a + 1) % nCount);
3212 					aSegment.setControlPointA(rCandidate.getNextControlPoint(a));
3213 					aSegment.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
3214 					aSegment.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
3215 
3216 					if(aSegment.isBezier())
3217 					{
3218 						double fExtremumPos(0.0);
3219 						sal_uInt32 nExtremumCounter(4);
3220 
3221 						while(nExtremumCounter-- && aSegment.isBezier() && aSegment.getMinimumExtremumPosition(fExtremumPos))
3222 						{
3223 							// split off left, now extremum-free part and append
3224 							B2DCubicBezier aLeft;
3225 
3226 							aSegment.split(fExtremumPos, &aLeft, &aSegment);
3227 		                    aLeft.testAndSolveTrivialBezier();
3228 		                    aSegment.testAndSolveTrivialBezier();
3229 
3230 							if(aLeft.isBezier())
3231 							{
3232 								aRetval.appendBezierSegment(aLeft.getControlPointA(), aLeft.getControlPointB(), aLeft.getEndPoint());
3233 							}
3234 							else
3235 							{
3236 								aRetval.append(aLeft.getEndPoint());
3237 							}
3238 						}
3239 
3240 						// append (evtl. reduced) rest of Segment
3241 						if(aSegment.isBezier())
3242 						{
3243 							aRetval.appendBezierSegment(aSegment.getControlPointA(), aSegment.getControlPointB(), aSegment.getEndPoint());
3244 						}
3245 						else
3246 						{
3247 							aRetval.append(aSegment.getEndPoint());
3248 						}
3249 					}
3250 					else
3251 					{
3252 						// simple edge, append end point
3253 						aRetval.append(aSegment.getEndPoint());
3254 					}
3255 
3256 					// prepare next edge
3257 					aSegment.setStartPoint(aSegment.getEndPoint());
3258 				}
3259 
3260 				// copy closed flag and check for double points
3261 				aRetval.setClosed(rCandidate.isClosed());
3262 				aRetval.removeDoublePoints();
3263 
3264 				return aRetval;
3265 			}
3266 			else
3267 			{
3268 				return rCandidate;
3269 			}
3270 		}
3271 
3272 		// #i76891#
3273 		B2DPolygon simplifyCurveSegments(const B2DPolygon& rCandidate)
3274 		{
3275 			const sal_uInt32 nPointCount(rCandidate.count());
3276 
3277 			if(nPointCount && rCandidate.areControlPointsUsed())
3278 			{
3279 				// prepare loop
3280 				const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
3281 				B2DPolygon aRetval;
3282 				B2DCubicBezier aBezier;
3283 				aBezier.setStartPoint(rCandidate.getB2DPoint(0));
3284 
3285 				// try to avoid costly reallocations
3286 				aRetval.reserve( nEdgeCount+1);
3287 
3288 				// add start point
3289 				aRetval.append(aBezier.getStartPoint());
3290 
3291 				for(sal_uInt32 a(0L); a < nEdgeCount; a++)
3292 				{
3293 					// get values for edge
3294 					const sal_uInt32 nNextIndex((a + 1) % nPointCount);
3295 					aBezier.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
3296 					aBezier.setControlPointA(rCandidate.getNextControlPoint(a));
3297 					aBezier.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
3298 					aBezier.testAndSolveTrivialBezier();
3299 
3300 					// still bezier?
3301 					if(aBezier.isBezier())
3302 					{
3303 						// add edge with control vectors
3304 						aRetval.appendBezierSegment(aBezier.getControlPointA(), aBezier.getControlPointB(), aBezier.getEndPoint());
3305 					}
3306 					else
3307 					{
3308 						// add edge
3309 						aRetval.append(aBezier.getEndPoint());
3310 					}
3311 
3312 					// next point
3313 					aBezier.setStartPoint(aBezier.getEndPoint());
3314 				}
3315 
3316 				if(rCandidate.isClosed())
3317 				{
3318 					// set closed flag, rescue control point and correct last double point
3319 					closeWithGeometryChange(aRetval);
3320 				}
3321 
3322 				return aRetval;
3323 			}
3324 			else
3325 			{
3326 				return rCandidate;
3327 			}
3328 		}
3329 
3330 		// makes the given indexed point the new polygon start point. To do that, the points in the
3331 		// polygon will be rotated. This is only valid for closed polygons, for non-closed ones
3332 		// an assertion will be triggered
3333 		B2DPolygon makeStartPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndexOfNewStatPoint)
3334 		{
3335 			const sal_uInt32 nPointCount(rCandidate.count());
3336 
3337 			if(nPointCount > 2 && nIndexOfNewStatPoint != 0 && nIndexOfNewStatPoint < nPointCount)
3338 			{
3339 				OSL_ENSURE(rCandidate.isClosed(), "makeStartPoint: only valid for closed polygons (!)");
3340 				B2DPolygon aRetval;
3341 
3342 				for(sal_uInt32 a(0); a < nPointCount; a++)
3343 				{
3344 					const sal_uInt32 nSourceIndex((a + nIndexOfNewStatPoint) % nPointCount);
3345 					aRetval.append(rCandidate.getB2DPoint(nSourceIndex));
3346 
3347 					if(rCandidate.areControlPointsUsed())
3348 					{
3349 						aRetval.setPrevControlPoint(a, rCandidate.getPrevControlPoint(nSourceIndex));
3350 						aRetval.setNextControlPoint(a, rCandidate.getNextControlPoint(nSourceIndex));
3351 					}
3352 				}
3353 
3354 				return aRetval;
3355 			}
3356 
3357 			return rCandidate;
3358 		}
3359 
3360 		B2DPolygon createEdgesOfGivenLength(const B2DPolygon& rCandidate, double fLength, double fStart, double fEnd)
3361 		{
3362 			B2DPolygon aRetval;
3363 
3364 			if(fLength < 0.0)
3365 			{
3366 				fLength = 0.0;
3367 			}
3368 
3369 			if(!fTools::equalZero(fLength))
3370 			{
3371 				if(fStart < 0.0)
3372 				{
3373 					fStart = 0.0;
3374 				}
3375 
3376 				if(fEnd < 0.0)
3377 				{
3378 					fEnd = 0.0;
3379 				}
3380 
3381 				if(fEnd < fStart)
3382 				{
3383 					fEnd = fStart;
3384 				}
3385 
3386 				// iterate and consume pieces with fLength. First subdivide to reduce input to line segments
3387 				const B2DPolygon aCandidate(rCandidate.areControlPointsUsed() ? rCandidate.getDefaultAdaptiveSubdivision() : rCandidate);
3388 				const sal_uInt32 nPointCount(aCandidate.count());
3389 
3390 				if(nPointCount > 1)
3391 				{
3392 					const bool bEndActive(!fTools::equalZero(fEnd));
3393 					const sal_uInt32 nEdgeCount(aCandidate.isClosed() ? nPointCount : nPointCount - 1);
3394 					B2DPoint aCurrent(aCandidate.getB2DPoint(0));
3395 					double fPositionInEdge(fStart);
3396 					double fAbsolutePosition(fStart);
3397 
3398 					for(sal_uInt32 a(0); a < nEdgeCount; a++)
3399 					{
3400 						const sal_uInt32 nNextIndex((a + 1) % nPointCount);
3401 						const B2DPoint aNext(aCandidate.getB2DPoint(nNextIndex));
3402 						const B2DVector aEdge(aNext - aCurrent);
3403 						double fEdgeLength(aEdge.getLength());
3404 
3405 						if(!fTools::equalZero(fEdgeLength))
3406 						{
3407 							while(fTools::less(fPositionInEdge, fEdgeLength))
3408 							{
3409 								// move position on edge forward as long as on edge
3410 								const double fScalar(fPositionInEdge / fEdgeLength);
3411 								aRetval.append(aCurrent + (aEdge * fScalar));
3412 								fPositionInEdge += fLength;
3413 
3414 								if(bEndActive)
3415 								{
3416 									fAbsolutePosition += fLength;
3417 
3418 									if(fTools::more(fAbsolutePosition, fEnd))
3419 									{
3420 										break;
3421 									}
3422 								}
3423 							}
3424 
3425 							// substract length of current edge
3426 							fPositionInEdge -= fEdgeLength;
3427 						}
3428 
3429 						if(bEndActive && fTools::more(fAbsolutePosition, fEnd))
3430 						{
3431 							break;
3432 						}
3433 
3434 						// prepare next step
3435 						aCurrent = aNext;
3436 					}
3437 
3438 					// keep closed state
3439 					aRetval.setClosed(aCandidate.isClosed());
3440 				}
3441 				else
3442 				{
3443 					// source polygon has only one point, return unchanged
3444 					aRetval = aCandidate;
3445 				}
3446 			}
3447 
3448 			return aRetval;
3449 		}
3450 
3451 		B2DPolygon createWaveline(const B2DPolygon& rCandidate, double fWaveWidth, double fWaveHeight)
3452 		{
3453 			B2DPolygon aRetval;
3454 
3455 			if(fWaveWidth < 0.0)
3456 			{
3457 				fWaveWidth = 0.0;
3458 			}
3459 
3460 			if(fWaveHeight < 0.0)
3461 			{
3462 				fWaveHeight = 0.0;
3463 			}
3464 
3465 			const bool bHasWidth(!fTools::equalZero(fWaveWidth));
3466 			const bool bHasHeight(!fTools::equalZero(fWaveHeight));
3467 
3468 			if(bHasWidth)
3469 			{
3470 				if(bHasHeight)
3471 				{
3472 					// width and height, create waveline. First subdivide to reduce input to line segments
3473 					// of WaveWidth. Last segment may be missing. If this turns out to be a problem, it
3474 					// may be added here again using the original last point from rCandidate. It may
3475 					// also be the case that rCandidate was closed. To simplify things it is handled here
3476 					// as if it was opened.
3477 					// Result from createEdgesOfGivenLength contains no curved segments, handle as straight
3478 					// edges.
3479 					const B2DPolygon aEqualLenghEdges(createEdgesOfGivenLength(rCandidate, fWaveWidth));
3480 					const sal_uInt32 nPointCount(aEqualLenghEdges.count());
3481 
3482 					if(nPointCount > 1)
3483 					{
3484 						// iterate over straight edges, add start point
3485 						B2DPoint aCurrent(aEqualLenghEdges.getB2DPoint(0));
3486 						aRetval.append(aCurrent);
3487 
3488 						for(sal_uInt32 a(0); a < nPointCount - 1; a++)
3489 						{
3490 							const sal_uInt32 nNextIndex((a + 1) % nPointCount);
3491 							const B2DPoint aNext(aEqualLenghEdges.getB2DPoint(nNextIndex));
3492 							const B2DVector aEdge(aNext - aCurrent);
3493 							const B2DVector aPerpendicular(getNormalizedPerpendicular(aEdge));
3494                             const B2DVector aControlOffset((aEdge * 0.467308) - (aPerpendicular * fWaveHeight));
3495 
3496 							// add curve segment
3497 							aRetval.appendBezierSegment(
3498 								aCurrent + aControlOffset,
3499 								aNext - aControlOffset,
3500 								aNext);
3501 
3502 							// prepare next step
3503 							aCurrent = aNext;
3504 						}
3505 					}
3506 				}
3507 				else
3508 				{
3509 					// width but no height -> return original polygon
3510 					aRetval = rCandidate;
3511 				}
3512 			}
3513 			else
3514 			{
3515 				// no width -> no waveline, stay empty and return
3516 			}
3517 
3518 			return aRetval;
3519 		}
3520 
3521         //////////////////////////////////////////////////////////////////////
3522 		// comparators with tolerance for 2D Polygons
3523 
3524 		bool equal(const B2DPolygon& rCandidateA, const B2DPolygon& rCandidateB, const double& rfSmallValue)
3525 		{
3526 			const sal_uInt32 nPointCount(rCandidateA.count());
3527 
3528 			if(nPointCount != rCandidateB.count())
3529 				return false;
3530 
3531 			const bool bClosed(rCandidateA.isClosed());
3532 
3533 			if(bClosed != rCandidateB.isClosed())
3534 				return false;
3535 
3536 			const bool bAreControlPointsUsed(rCandidateA.areControlPointsUsed());
3537 
3538 			if(bAreControlPointsUsed != rCandidateB.areControlPointsUsed())
3539 				return false;
3540 
3541 			for(sal_uInt32 a(0); a < nPointCount; a++)
3542 			{
3543 				const B2DPoint aPoint(rCandidateA.getB2DPoint(a));
3544 
3545 				if(!aPoint.equal(rCandidateB.getB2DPoint(a), rfSmallValue))
3546 					return false;
3547 
3548 				if(bAreControlPointsUsed)
3549 				{
3550 					const basegfx::B2DPoint aPrev(rCandidateA.getPrevControlPoint(a));
3551 
3552 					if(!aPrev.equal(rCandidateB.getPrevControlPoint(a), rfSmallValue))
3553 						return false;
3554 
3555 					const basegfx::B2DPoint aNext(rCandidateA.getNextControlPoint(a));
3556 
3557 					if(!aNext.equal(rCandidateB.getNextControlPoint(a), rfSmallValue))
3558 						return false;
3559 				}
3560 			}
3561 
3562 			return true;
3563 		}
3564 
3565 		bool equal(const B2DPolygon& rCandidateA, const B2DPolygon& rCandidateB)
3566 		{
3567 			const double fSmallValue(fTools::getSmallValue());
3568 
3569 			return equal(rCandidateA, rCandidateB, fSmallValue);
3570 		}
3571 
3572 		// snap points of horizontal or vertical edges to discrete values
3573 		B2DPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolygon& rCandidate)
3574 		{
3575 			const sal_uInt32 nPointCount(rCandidate.count());
3576 
3577 			if(nPointCount > 1)
3578 			{
3579 				// Start by copying the source polygon to get a writeable copy. The closed state is
3580 				// copied by aRetval's initialisation, too, so no need to copy it in this method
3581 				B2DPolygon aRetval(rCandidate);
3582 
3583 				// prepare geometry data. Get rounded from original
3584                 B2ITuple aPrevTuple(basegfx::fround(rCandidate.getB2DPoint(nPointCount - 1)));
3585 				B2DPoint aCurrPoint(rCandidate.getB2DPoint(0));
3586 				B2ITuple aCurrTuple(basegfx::fround(aCurrPoint));
3587 
3588 				// loop over all points. This will also snap the implicit closing edge
3589 				// even when not closed, but that's no problem here
3590 				for(sal_uInt32 a(0); a < nPointCount; a++)
3591 				{
3592 					// get next point. Get rounded from original
3593                     const bool bLastRun(a + 1 == nPointCount);
3594                     const sal_uInt32 nNextIndex(bLastRun ? 0 : a + 1);
3595 					const B2DPoint aNextPoint(rCandidate.getB2DPoint(nNextIndex));
3596 					const B2ITuple aNextTuple(basegfx::fround(aNextPoint));
3597 
3598 					// get the states
3599 					const bool bPrevVertical(aPrevTuple.getX() == aCurrTuple.getX());
3600 					const bool bNextVertical(aNextTuple.getX() == aCurrTuple.getX());
3601 					const bool bPrevHorizontal(aPrevTuple.getY() == aCurrTuple.getY());
3602 					const bool bNextHorizontal(aNextTuple.getY() == aCurrTuple.getY());
3603 					const bool bSnapX(bPrevVertical || bNextVertical);
3604 					const bool bSnapY(bPrevHorizontal || bNextHorizontal);
3605 
3606 					if(bSnapX || bSnapY)
3607 					{
3608 						const B2DPoint aSnappedPoint(
3609 							bSnapX ? aCurrTuple.getX() : aCurrPoint.getX(),
3610 							bSnapY ? aCurrTuple.getY() : aCurrPoint.getY());
3611 
3612 						aRetval.setB2DPoint(a, aSnappedPoint);
3613 					}
3614 
3615 					// prepare next point
3616                     if(!bLastRun)
3617                     {
3618     					aPrevTuple = aCurrTuple;
3619 	    				aCurrPoint = aNextPoint;
3620 		    			aCurrTuple = aNextTuple;
3621                     }
3622 				}
3623 
3624 				return aRetval;
3625 			}
3626 			else
3627 			{
3628 				return rCandidate;
3629 			}
3630 		}
3631 
3632 	} // end of namespace tools
3633 } // end of namespace basegfx
3634 
3635 //////////////////////////////////////////////////////////////////////////////
3636 // eof
3637