xref: /AOO41X/main/tools/source/generic/poly.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_tools.hxx"
30 
31 #define _SV_POLY_CXX
32 #include <osl/endian.h>
33 #include <tools/bigint.hxx>
34 #include <tools/debug.hxx>
35 #include <tools/stream.hxx>
36 #include <tools/vcompat.hxx>
37 #include <poly.h>
38 #include <tools/line.hxx>
39 #ifndef _VECTOR2D_H
40 #include <tools/vector2d.hxx>
41 #endif
42 #ifndef _POLY_HXX
43 #include <tools/poly.hxx>
44 #endif
45 #include <basegfx/polygon/b2dpolygon.hxx>
46 #include <basegfx/point/b2dpoint.hxx>
47 #include <basegfx/vector/b2dvector.hxx>
48 #include <basegfx/polygon/b2dpolygontools.hxx>
49 #include <basegfx/curve/b2dcubicbezier.hxx>
50 
51 #include <vector>
52 #include <iterator>
53 #include <algorithm>
54 #include <cstring>
55 #include <limits.h>
56 #include <cmath>
57 
58 
59 // =======================================================================
60 
61 DBG_NAME( Polygon )
62 
63 // -----------------------------------------------------------------------
64 
65 #define EDGE_LEFT		1
66 #define EDGE_TOP		2
67 #define EDGE_RIGHT		4
68 #define EDGE_BOTTOM 	8
69 #define EDGE_HORZ		(EDGE_RIGHT | EDGE_LEFT)
70 #define EDGE_VERT		(EDGE_TOP | EDGE_BOTTOM)
71 #define	SMALL_DVALUE	0.0000001
72 #define FSQRT2			1.4142135623730950488016887242097
73 
74 // -----------------------------------------------------------------------
75 
76 static ImplPolygonData aStaticImplPolygon =
77 {
78 	NULL, NULL, 0, 0
79 };
80 
81 // =======================================================================
82 
83 ImplPolygon::ImplPolygon( sal_uInt16 nInitSize, sal_Bool bFlags  )
84 {
85 	if ( nInitSize )
86 	{
87 		mpPointAry = (Point*)new char[(sal_uIntPtr)nInitSize*sizeof(Point)];
88 		memset( mpPointAry, 0, (sal_uIntPtr)nInitSize*sizeof(Point) );
89 	}
90 	else
91 		mpPointAry = NULL;
92 
93 	if( bFlags )
94 	{
95 		mpFlagAry = new sal_uInt8[ nInitSize ];
96 		memset( mpPointAry, 0, nInitSize );
97 	}
98 	else
99 		mpFlagAry = NULL;
100 
101 	mnRefCount = 1;
102 	mnPoints = nInitSize;
103 }
104 
105 // -----------------------------------------------------------------------
106 
107 ImplPolygon::ImplPolygon( const ImplPolygon& rImpPoly )
108 {
109 	if ( rImpPoly.mnPoints )
110 	{
111 		mpPointAry = (Point*)new char[(sal_uIntPtr)rImpPoly.mnPoints*sizeof(Point)];
112 		memcpy( mpPointAry, rImpPoly.mpPointAry, (sal_uIntPtr)rImpPoly.mnPoints*sizeof(Point) );
113 
114 		if( rImpPoly.mpFlagAry )
115 		{
116 			mpFlagAry = new sal_uInt8[ rImpPoly.mnPoints ];
117 			memcpy( mpFlagAry, rImpPoly.mpFlagAry, rImpPoly.mnPoints );
118 		}
119 		else
120 			mpFlagAry = NULL;
121 	}
122 	else
123 	{
124 		mpPointAry = NULL;
125 		mpFlagAry = NULL;
126 	}
127 
128 	mnRefCount = 1;
129 	mnPoints   = rImpPoly.mnPoints;
130 }
131 
132 // -----------------------------------------------------------------------
133 
134 ImplPolygon::ImplPolygon( sal_uInt16 nInitSize, const Point* pInitAry, const sal_uInt8* pInitFlags )
135 {
136 	if ( nInitSize )
137 	{
138 		mpPointAry = (Point*)new char[(sal_uIntPtr)nInitSize*sizeof(Point)];
139 		memcpy( mpPointAry, pInitAry, (sal_uIntPtr)nInitSize*sizeof( Point ) );
140 
141 		if( pInitFlags )
142 		{
143 			mpFlagAry = new sal_uInt8[ nInitSize ];
144 			memcpy( mpFlagAry, pInitFlags, nInitSize );
145 		}
146 		else
147 			mpFlagAry = NULL;
148 	}
149 	else
150 	{
151 		mpPointAry = NULL;
152 		mpFlagAry  = NULL;
153 	}
154 
155 	mnRefCount = 1;
156 	mnPoints   = nInitSize;
157 }
158 
159 // -----------------------------------------------------------------------
160 
161 ImplPolygon::~ImplPolygon()
162 {
163 	if ( mpPointAry )
164 	{
165 		delete[] (char*) mpPointAry;
166 	}
167 
168 	if( mpFlagAry )
169 		delete[] mpFlagAry;
170 }
171 
172 // -----------------------------------------------------------------------
173 
174 void ImplPolygon::ImplSetSize( sal_uInt16 nNewSize, sal_Bool bResize )
175 {
176 	if( mnPoints == nNewSize )
177 		return;
178 
179 	Point* pNewAry;
180 
181 	if ( nNewSize )
182 	{
183 		pNewAry = (Point*)new char[(sal_uIntPtr)nNewSize*sizeof(Point)];
184 
185 		if ( bResize )
186 		{
187 			// Alte Punkte kopieren
188 			if ( mnPoints < nNewSize )
189 			{
190 				// Neue Punkte mit 0 initialisieren
191 				memset( pNewAry+mnPoints, 0, (sal_uIntPtr)(nNewSize-mnPoints)*sizeof(Point) );
192 				if ( mpPointAry )
193 					memcpy( pNewAry, mpPointAry, mnPoints*sizeof(Point) );
194 			}
195 			else
196 			{
197 				if ( mpPointAry )
198 					memcpy( pNewAry, mpPointAry, (sal_uIntPtr)nNewSize*sizeof(Point) );
199 			}
200 		}
201 	}
202 	else
203 		pNewAry = NULL;
204 
205 	if ( mpPointAry )
206 		delete[] (char*) mpPointAry;
207 
208 	// ggf. FlagArray beruecksichtigen
209 	if( mpFlagAry )
210 	{
211 		sal_uInt8* pNewFlagAry;
212 
213 		if( nNewSize )
214 		{
215 			pNewFlagAry = new sal_uInt8[ nNewSize ];
216 
217 			if( bResize )
218 			{
219 				// Alte Flags kopieren
220 				if ( mnPoints < nNewSize )
221 				{
222 					// Neue Punkte mit 0 initialisieren
223 					memset( pNewFlagAry+mnPoints, 0, nNewSize-mnPoints );
224 					memcpy( pNewFlagAry, mpFlagAry, mnPoints );
225 				}
226 				else
227 					memcpy( pNewFlagAry, mpFlagAry, nNewSize );
228 			}
229 		}
230 		else
231 			pNewFlagAry = NULL;
232 
233 		delete[] mpFlagAry;
234 		mpFlagAry  = pNewFlagAry;
235 	}
236 
237 	mpPointAry = pNewAry;
238 	mnPoints   = nNewSize;
239 }
240 
241 // -----------------------------------------------------------------------
242 
243 void ImplPolygon::ImplSplit( sal_uInt16 nPos, sal_uInt16 nSpace, ImplPolygon* pInitPoly )
244 {
245 	const sal_uIntPtr 	nSpaceSize = nSpace * sizeof( Point );
246 
247 	//Can't fit this in :-(, throw ?
248 	if (mnPoints + nSpace > USHRT_MAX)
249 		return;
250 
251 	const sal_uInt16	nNewSize = mnPoints + nSpace;
252 
253 	if( nPos >= mnPoints )
254 	{
255 		// Hinten anhaengen
256 		nPos = mnPoints;
257 		ImplSetSize( nNewSize, sal_True );
258 
259 		if( pInitPoly )
260 		{
261 			memcpy( mpPointAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
262 
263 			if( pInitPoly->mpFlagAry )
264 				memcpy( mpFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
265 		}
266 	}
267 	else
268 	{
269 		// PointArray ist in diesem Zweig immer vorhanden
270 		const sal_uInt16	nSecPos = nPos + nSpace;
271 		const sal_uInt16	nRest = mnPoints - nPos;
272 
273 		Point* pNewAry = (Point*) new char[ (sal_uIntPtr) nNewSize * sizeof( Point ) ];
274 
275 		memcpy( pNewAry, mpPointAry, nPos * sizeof( Point ) );
276 
277 		if( pInitPoly )
278 			memcpy( pNewAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
279 		else
280 			memset( pNewAry + nPos, 0, nSpaceSize );
281 
282 		memcpy( pNewAry + nSecPos, mpPointAry + nPos, nRest * sizeof( Point ) );
283 		delete[] (char*) mpPointAry;
284 
285 		// ggf. FlagArray beruecksichtigen
286 		if( mpFlagAry )
287 		{
288 			sal_uInt8* pNewFlagAry = new sal_uInt8[ nNewSize ];
289 
290 			memcpy( pNewFlagAry, mpFlagAry, nPos );
291 
292 			if( pInitPoly && pInitPoly->mpFlagAry )
293 				memcpy( pNewFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
294 			else
295 				memset( pNewFlagAry + nPos, 0, nSpace );
296 
297 			memcpy( pNewFlagAry + nSecPos, mpFlagAry + nPos, nRest );
298 			delete[] mpFlagAry;
299 			mpFlagAry = pNewFlagAry;
300 		}
301 
302 		mpPointAry = pNewAry;
303 		mnPoints   = nNewSize;
304 	}
305 }
306 
307 // -----------------------------------------------------------------------
308 
309 void ImplPolygon::ImplRemove( sal_uInt16 nPos, sal_uInt16 nCount )
310 {
311 	const sal_uInt16 nRemoveCount = Min( (sal_uInt16) ( mnPoints - nPos ), (sal_uInt16) nCount );
312 
313 	if( nRemoveCount )
314 	{
315 		const sal_uInt16	nNewSize = mnPoints - nRemoveCount;
316 		const sal_uInt16	nSecPos = nPos + nRemoveCount;
317 		const sal_uInt16	nRest = mnPoints - nSecPos;
318 
319 		Point* pNewAry = (Point*) new char[ (sal_uIntPtr) nNewSize * sizeof( Point ) ];
320 
321 		memcpy( pNewAry, mpPointAry, nPos * sizeof( Point ) );
322 		memcpy( pNewAry + nPos, mpPointAry + nSecPos, nRest * sizeof( Point ) );
323 
324 		delete[] (char*) mpPointAry;
325 
326 		// ggf. FlagArray beruecksichtigen
327 		if( mpFlagAry )
328 		{
329 			sal_uInt8* pNewFlagAry = new sal_uInt8[ nNewSize ];
330 
331 			memcpy( pNewFlagAry, mpFlagAry, nPos );
332 			memcpy( pNewFlagAry + nPos, mpFlagAry + nSecPos, nRest );
333 			delete[] mpFlagAry;
334 			mpFlagAry = pNewFlagAry;
335 		}
336 
337 		mpPointAry = pNewAry;
338 		mnPoints   = nNewSize;
339 	}
340 }
341 
342 // -----------------------------------------------------------------------
343 
344 void ImplPolygon::ImplCreateFlagArray()
345 {
346 	if( !mpFlagAry )
347 	{
348 		mpFlagAry = new sal_uInt8[ mnPoints ];
349 		memset( mpFlagAry, 0, mnPoints );
350 	}
351 }
352 
353 // =======================================================================
354 
355 inline void Polygon::ImplMakeUnique()
356 {
357 	// Falls noch andere Referenzen bestehen, dann kopieren
358 	if ( mpImplPolygon->mnRefCount != 1 )
359 	{
360 		if ( mpImplPolygon->mnRefCount )
361 			mpImplPolygon->mnRefCount--;
362 		mpImplPolygon = new ImplPolygon( *mpImplPolygon );
363 	}
364 }
365 
366 // -----------------------------------------------------------------------
367 
368 inline double ImplGetAngle( const Point& rCenter, const Point& rPt )
369 {
370 	const long nDX = rPt.X() - rCenter.X();
371 	return( atan2( -rPt.Y() + rCenter.Y(), ( ( nDX == 0L ) ? 0.000000001 : nDX ) ) );
372 }
373 
374 // -----------------------------------------------------------------------
375 
376 Polygon::Polygon()
377 {
378 	DBG_CTOR( Polygon, NULL );
379 	mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
380 }
381 
382 // -----------------------------------------------------------------------
383 
384 Polygon::Polygon( sal_uInt16 nSize )
385 {
386 	DBG_CTOR( Polygon, NULL );
387 
388 	if ( nSize )
389 		mpImplPolygon = new ImplPolygon( nSize );
390 	else
391 		mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
392 }
393 
394 // -----------------------------------------------------------------------
395 
396 Polygon::Polygon( sal_uInt16 nPoints, const Point* pPtAry, const sal_uInt8* pFlagAry )
397 {
398 	DBG_CTOR( Polygon, NULL );
399 
400 	if( nPoints )
401 		mpImplPolygon = new ImplPolygon( nPoints, pPtAry, pFlagAry );
402 	else
403 		mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
404 }
405 
406 // -----------------------------------------------------------------------
407 
408 Polygon::Polygon( const Polygon& rPoly )
409 {
410 	DBG_CTOR( Polygon, NULL );
411 	DBG_CHKOBJ( &rPoly, Polygon, NULL );
412 	DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
413 
414 	mpImplPolygon = rPoly.mpImplPolygon;
415 	if ( mpImplPolygon->mnRefCount )
416 		mpImplPolygon->mnRefCount++;
417 }
418 
419 // -----------------------------------------------------------------------
420 
421 Polygon::Polygon( const Rectangle& rRect )
422 {
423 	DBG_CTOR( Polygon, NULL );
424 
425 	if ( rRect.IsEmpty() )
426 		mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
427 	else
428 	{
429 		mpImplPolygon = new ImplPolygon( 5 );
430 		mpImplPolygon->mpPointAry[0] = rRect.TopLeft();
431 		mpImplPolygon->mpPointAry[1] = rRect.TopRight();
432 		mpImplPolygon->mpPointAry[2] = rRect.BottomRight();
433 		mpImplPolygon->mpPointAry[3] = rRect.BottomLeft();
434 		mpImplPolygon->mpPointAry[4] = rRect.TopLeft();
435 	}
436 }
437 
438 // -----------------------------------------------------------------------
439 
440 Polygon::Polygon( const Rectangle& rRect, sal_uIntPtr nHorzRound, sal_uIntPtr nVertRound )
441 {
442 	DBG_CTOR( Polygon, NULL );
443 
444 	if ( rRect.IsEmpty() )
445 		mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
446 	else
447 	{
448 		Rectangle aRect( rRect );
449 		aRect.Justify();			// SJ: i9140
450 
451 		nHorzRound = Min( nHorzRound, (sal_uIntPtr) labs( aRect.GetWidth() >> 1 ) );
452 		nVertRound = Min( nVertRound, (sal_uIntPtr) labs( aRect.GetHeight() >> 1 ) );
453 
454 		if( !nHorzRound && !nVertRound )
455 		{
456 			mpImplPolygon = new ImplPolygon( 5 );
457 			mpImplPolygon->mpPointAry[0] = aRect.TopLeft();
458 			mpImplPolygon->mpPointAry[1] = aRect.TopRight();
459 			mpImplPolygon->mpPointAry[2] = aRect.BottomRight();
460 			mpImplPolygon->mpPointAry[3] = aRect.BottomLeft();
461 			mpImplPolygon->mpPointAry[4] = aRect.TopLeft();
462 		}
463 		else
464 		{
465 			const Point		aTL( aRect.Left() + nHorzRound, aRect.Top() + nVertRound );
466 			const Point		aTR( aRect.Right() - nHorzRound, aRect.Top() + nVertRound );
467 			const Point		aBR( aRect.Right() - nHorzRound, aRect.Bottom() - nVertRound );
468 			const Point		aBL( aRect.Left() + nHorzRound, aRect.Bottom() - nVertRound );
469 			Polygon*		pEllipsePoly = new Polygon( Point(), nHorzRound, nVertRound );
470 			sal_uInt16			i, nEnd, nSize4 = pEllipsePoly->GetSize() >> 2;
471 
472 			mpImplPolygon = new ImplPolygon( pEllipsePoly->GetSize() + 1 );
473 
474 			const Point*	pSrcAry = pEllipsePoly->GetConstPointAry();
475 			Point*			pDstAry = mpImplPolygon->mpPointAry;
476 
477 			for( i = 0, nEnd = nSize4; i < nEnd; i++ )
478 				( pDstAry[ i ] = pSrcAry[ i ] ) += aTR;
479 
480 			for( nEnd = nEnd + nSize4; i < nEnd; i++ )
481 				( pDstAry[ i ] = pSrcAry[ i ] ) += aTL;
482 
483 			for( nEnd = nEnd + nSize4; i < nEnd; i++ )
484 				( pDstAry[ i ] = pSrcAry[ i ] ) += aBL;
485 
486 			for( nEnd = nEnd + nSize4; i < nEnd; i++ )
487 				( pDstAry[ i ] = pSrcAry[ i ] ) += aBR;
488 
489 			pDstAry[ nEnd ] = pDstAry[ 0 ];
490 			delete pEllipsePoly;
491 		}
492 	}
493 }
494 
495 // -----------------------------------------------------------------------
496 
497 Polygon::Polygon( const Point& rCenter, long nRadX, long nRadY, sal_uInt16 nPoints )
498 {
499 	DBG_CTOR( Polygon, NULL );
500 
501 	if( nRadX && nRadY )
502 	{
503 		// Default berechnen (abhaengig von Groesse)
504 		if( !nPoints )
505 		{
506 			nPoints = (sal_uInt16) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
507 								 sqrt( (double) labs( nRadX * nRadY ) ) ) );
508 
509 			nPoints = (sal_uInt16) MinMax( nPoints, 32, 256 );
510 
511 			if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
512 				nPoints >>= 1;
513 		}
514 
515 		// Anzahl der Punkte auf durch 4 teilbare Zahl aufrunden
516 		mpImplPolygon = new ImplPolygon( nPoints = (nPoints + 3) & ~3 );
517 
518 		Point* pPt;
519 		sal_uInt16 i;
520 		sal_uInt16 nPoints2 = nPoints >> 1;
521 		sal_uInt16 nPoints4 = nPoints >> 2;
522 		double nAngle;
523 		double nAngleStep = F_PI2 / ( nPoints4 - 1 );
524 
525 		for( i=0, nAngle = 0.0; i < nPoints4; i++, nAngle += nAngleStep )
526 		{
527 			long nX = FRound( nRadX * cos( nAngle ) );
528 			long nY = FRound( -nRadY * sin( nAngle ) );
529 
530 			pPt = &(mpImplPolygon->mpPointAry[i]);
531 			pPt->X() =	nX + rCenter.X();
532 			pPt->Y() =	nY + rCenter.Y();
533 			pPt = &(mpImplPolygon->mpPointAry[nPoints2-i-1]);
534 			pPt->X() = -nX + rCenter.X();
535 			pPt->Y() =	nY + rCenter.Y();
536 			pPt = &(mpImplPolygon->mpPointAry[i+nPoints2]);
537 			pPt->X() = -nX + rCenter.X();
538 			pPt->Y() = -nY + rCenter.Y();
539 			pPt = &(mpImplPolygon->mpPointAry[nPoints-i-1]);
540 			pPt->X() =	nX + rCenter.X();
541 			pPt->Y() = -nY + rCenter.Y();
542 		}
543 	}
544 	else
545 		mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
546 }
547 
548 // -----------------------------------------------------------------------
549 
550 Polygon::Polygon( const Rectangle& rBound,
551 				  const Point& rStart, const Point& rEnd, PolyStyle eStyle )
552 {
553 	DBG_CTOR( Polygon, NULL );
554 
555 	const long	nWidth = rBound.GetWidth();
556 	const long	nHeight = rBound.GetHeight();
557 
558 	if( ( nWidth > 1 ) && ( nHeight > 1 ) )
559 	{
560 		const Point aCenter( rBound.Center() );
561 		const long	nRadX = aCenter.X() - rBound.Left();
562 		const long	nRadY = aCenter.Y() - rBound.Top();
563 		sal_uInt16		nPoints;
564 
565 		nPoints = (sal_uInt16) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
566 							 sqrt( (double) labs( nRadX * nRadY ) ) ) );
567 
568 		nPoints = (sal_uInt16) MinMax( nPoints, 32, 256 );
569 
570 		if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
571 			nPoints >>= 1;
572 
573 		// Winkel berechnen
574 		const double	fRadX = nRadX;
575 		const double	fRadY = nRadY;
576 		const double	fCenterX = aCenter.X();
577 		const double	fCenterY = aCenter.Y();
578 		double			fStart = ImplGetAngle( aCenter, rStart );
579 		double			fEnd = ImplGetAngle( aCenter, rEnd );
580 		double			fDiff = fEnd - fStart;
581 		double			fStep;
582 		sal_uInt16			nStart;
583 		sal_uInt16			nEnd;
584 
585 		if( fDiff < 0. )
586 			fDiff += F_2PI;
587 
588 		// Punktanzahl proportional verkleinern ( fDiff / (2PI) );
589 		// ist eingentlich nur fuer einen Kreis richtig; wir
590 		// machen es hier aber trotzdem
591 		nPoints = Max( (sal_uInt16) ( ( fDiff * 0.1591549 ) * nPoints ), (sal_uInt16) 16 );
592 		fStep = fDiff / ( nPoints - 1 );
593 
594 		if( POLY_PIE == eStyle )
595 		{
596 			const Point aCenter2( FRound( fCenterX ), FRound( fCenterY ) );
597 
598 			nStart = 1;
599 			nEnd = nPoints + 1;
600 			mpImplPolygon = new ImplPolygon( nPoints + 2 );
601 			mpImplPolygon->mpPointAry[ 0 ] = aCenter2;
602 			mpImplPolygon->mpPointAry[ nEnd ] = aCenter2;
603 		}
604 		else
605 		{
606 			mpImplPolygon = new ImplPolygon( ( POLY_CHORD == eStyle ) ? ( nPoints + 1 ) : nPoints );
607 			nStart = 0;
608 			nEnd = nPoints;
609 		}
610 
611 		for(; nStart < nEnd; nStart++, fStart += fStep )
612 		{
613 			Point& rPt = mpImplPolygon->mpPointAry[ nStart ];
614 
615 			rPt.X() = FRound( fCenterX + fRadX * cos( fStart ) );
616 			rPt.Y() = FRound( fCenterY - fRadY * sin( fStart ) );
617 		}
618 
619 		if( POLY_CHORD == eStyle )
620 			mpImplPolygon->mpPointAry[ nPoints ] = mpImplPolygon->mpPointAry[ 0 ];
621 	}
622 	else
623 		mpImplPolygon = (ImplPolygon*) &aStaticImplPolygon;
624 }
625 
626 // -----------------------------------------------------------------------
627 
628 Polygon::Polygon( const Point& rBezPt1, const Point& rCtrlPt1,
629 				  const Point& rBezPt2, const Point& rCtrlPt2,
630 				  sal_uInt16 nPoints )
631 {
632 	DBG_CTOR( Polygon, NULL );
633 
634 	nPoints = ( 0 == nPoints ) ? 25 : ( ( nPoints < 2 ) ? 2 : nPoints );
635 
636 	const double	fInc = 1.0 / ( nPoints - 1 );
637 	double			fK_1 = 0.0, fK1_1 = 1.0;
638 	double			fK_2, fK_3, fK1_2, fK1_3, fK12, fK21;
639 	const double	fX0 = rBezPt1.X();
640 	const double	fY0 = rBezPt1.Y();
641 	const double	fX1 = 3.0 * rCtrlPt1.X();
642 	const double	fY1 = 3.0 * rCtrlPt1.Y();
643 	const double	fX2 = 3.0 * rCtrlPt2.X();;
644 	const double	fY2 = 3.0 * rCtrlPt2.Y();;
645 	const double	fX3 = rBezPt2.X();
646 	const double	fY3 = rBezPt2.Y();
647 
648 	mpImplPolygon = new ImplPolygon( nPoints );
649 
650 	for( sal_uInt16 i = 0; i < nPoints; i++, fK_1 += fInc, fK1_1 -= fInc )
651 	{
652 		Point& rPt = mpImplPolygon->mpPointAry[ i ];
653 
654 		fK_2 = fK_1, fK_3 = ( fK_2 *= fK_1 ), fK_3 *= fK_1;
655 		fK1_2 = fK1_1, fK1_3 = ( fK1_2 *= fK1_1 ), fK1_3 *= fK1_1;
656 		fK12 = fK_1 * fK1_2, fK21 = fK_2 * fK1_1;
657 
658 		rPt.X() = FRound( fK1_3 * fX0 + fK12 * fX1 + fK21 * fX2 + fK_3 * fX3 );
659 		rPt.Y() = FRound( fK1_3 * fY0 + fK12 * fY1 + fK21 * fY2 + fK_3 * fY3 );
660 	}
661 }
662 
663 // -----------------------------------------------------------------------
664 
665 Polygon::~Polygon()
666 {
667 	DBG_DTOR( Polygon, NULL );
668 
669 	// Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
670 	// die letzte Referenz ist, sonst Referenzcounter decrementieren
671 	if ( mpImplPolygon->mnRefCount )
672 	{
673 		if ( mpImplPolygon->mnRefCount > 1 )
674 			mpImplPolygon->mnRefCount--;
675 		else
676 			delete mpImplPolygon;
677 	}
678 }
679 
680 // -----------------------------------------------------------------------
681 
682 Point* Polygon::ImplGetPointAry()
683 {
684 	DBG_CHKTHIS( Polygon, NULL );
685 
686 	ImplMakeUnique();
687 	return (Point*)mpImplPolygon->mpPointAry;
688 }
689 
690 // -----------------------------------------------------------------------
691 
692 sal_uInt8* Polygon::ImplGetFlagAry()
693 {
694 	DBG_CHKTHIS( Polygon, NULL );
695 
696 	ImplMakeUnique();
697 	mpImplPolygon->ImplCreateFlagArray();
698 	return mpImplPolygon->mpFlagAry;
699 }
700 
701 // -----------------------------------------------------------------------
702 
703 const Point* Polygon::GetConstPointAry() const
704 {
705 	DBG_CHKTHIS( Polygon, NULL );
706 	return (Point*)mpImplPolygon->mpPointAry;
707 }
708 
709 // -----------------------------------------------------------------------
710 
711 const sal_uInt8* Polygon::GetConstFlagAry() const
712 {
713 	DBG_CHKTHIS( Polygon, NULL );
714 	return mpImplPolygon->mpFlagAry;
715 }
716 
717 // -----------------------------------------------------------------------
718 
719 void Polygon::SetPoint( const Point& rPt, sal_uInt16 nPos )
720 {
721 	DBG_CHKTHIS( Polygon, NULL );
722 	DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
723 				"Polygon::SetPoint(): nPos >= nPoints" );
724 
725 	ImplMakeUnique();
726 	mpImplPolygon->mpPointAry[nPos] = rPt;
727 }
728 
729 // -----------------------------------------------------------------------
730 
731 void Polygon::SetFlags( sal_uInt16 nPos, PolyFlags eFlags )
732 {
733 	DBG_CHKTHIS( Polygon, NULL );
734 	DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
735 				"Polygon::SetFlags(): nPos >= nPoints" );
736 
737 	// we do only want to create the flag array if there
738 	// is at least one flag different to POLY_NORMAL
739 	if ( mpImplPolygon || ( eFlags != POLY_NORMAL ) )
740 	{
741 		ImplMakeUnique();
742 		mpImplPolygon->ImplCreateFlagArray();
743 		mpImplPolygon->mpFlagAry[ nPos ] = (sal_uInt8) eFlags;
744 	}
745 }
746 
747 // -----------------------------------------------------------------------
748 
749 const Point& Polygon::GetPoint( sal_uInt16 nPos ) const
750 {
751 	DBG_CHKTHIS( Polygon, NULL );
752 	DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
753 				"Polygon::GetPoint(): nPos >= nPoints" );
754 
755 	return mpImplPolygon->mpPointAry[nPos];
756 }
757 
758 // -----------------------------------------------------------------------
759 
760 PolyFlags Polygon::GetFlags( sal_uInt16 nPos ) const
761 {
762 	DBG_CHKTHIS( Polygon, NULL );
763 	DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
764 				"Polygon::GetFlags(): nPos >= nPoints" );
765 	return( mpImplPolygon->mpFlagAry ?
766 			(PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] :
767 			POLY_NORMAL );
768 }
769 
770 // -----------------------------------------------------------------------
771 
772 sal_Bool Polygon::HasFlags() const
773 {
774 	return mpImplPolygon->mpFlagAry != NULL;
775 }
776 
777 // -----------------------------------------------------------------------
778 
779 sal_Bool Polygon::IsControl(sal_uInt16 nPos) const
780 {
781 	DBG_CHKTHIS( Polygon, NULL );
782 	DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
783 				"Polygon::GetFlags(): nPos >= nPoints" );
784 	PolyFlags eFlags = mpImplPolygon->mpFlagAry ?
785 					   (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] : POLY_NORMAL;
786 
787 	return( POLY_CONTROL == eFlags );
788 }
789 
790 // -----------------------------------------------------------------------
791 
792 sal_Bool Polygon::IsSmooth(sal_uInt16 nPos) const
793 {
794 	DBG_CHKTHIS( Polygon, NULL );
795 	DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
796 				"Polygon::GetFlags(): nPos >= nPoints" );
797 	PolyFlags eFlags = mpImplPolygon->mpFlagAry ?
798 					   (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] : POLY_NORMAL;
799 
800 	return( ( POLY_SMOOTH == eFlags ) || ( POLY_SYMMTR == eFlags ) );
801 }
802 
803 // -----------------------------------------------------------------------
804 
805 sal_Bool Polygon::IsRect() const
806 {
807 	sal_Bool bIsRect = sal_False;
808 	if ( mpImplPolygon->mpFlagAry == NULL )
809 	{
810 		if ( ( ( mpImplPolygon->mnPoints == 5 ) && ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ 4 ] ) ) ||
811 				( mpImplPolygon->mnPoints == 4 ) )
812 		{
813 			if ( ( mpImplPolygon->mpPointAry[ 0 ].X() == mpImplPolygon->mpPointAry[ 3 ].X() ) &&
814 					( mpImplPolygon->mpPointAry[ 0 ].Y() == mpImplPolygon->mpPointAry[ 1 ].Y() ) &&
815 						( mpImplPolygon->mpPointAry[ 1 ].X() == mpImplPolygon->mpPointAry[ 2 ].X() ) &&
816 							( mpImplPolygon->mpPointAry[ 2 ].Y() == mpImplPolygon->mpPointAry[ 3 ].Y() ) )
817 				bIsRect = sal_True;
818 		}
819 	}
820 	return bIsRect;
821 }
822 
823 // -----------------------------------------------------------------------
824 
825 void Polygon::SetSize( sal_uInt16 nNewSize )
826 {
827 	DBG_CHKTHIS( Polygon, NULL );
828 
829 	if( nNewSize != mpImplPolygon->mnPoints )
830 	{
831 		ImplMakeUnique();
832 		mpImplPolygon->ImplSetSize( nNewSize );
833 	}
834 }
835 
836 // -----------------------------------------------------------------------
837 
838 sal_uInt16 Polygon::GetSize() const
839 {
840 	DBG_CHKTHIS( Polygon, NULL );
841 
842 	return mpImplPolygon->mnPoints;
843 }
844 
845 // -----------------------------------------------------------------------
846 
847 void Polygon::Clear()
848 {
849 	DBG_CHKTHIS( Polygon, NULL );
850 
851 	if ( mpImplPolygon->mnRefCount )
852 	{
853 		if ( mpImplPolygon->mnRefCount > 1 )
854 			mpImplPolygon->mnRefCount--;
855 		else
856 			delete mpImplPolygon;
857 	}
858 
859 	mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
860 }
861 
862 // -----------------------------------------------------------------------
863 
864 double Polygon::CalcDistance( sal_uInt16 nP1, sal_uInt16 nP2 )
865 {
866 	DBG_ASSERT( nP1 < mpImplPolygon->mnPoints,
867 				"Polygon::CalcDistance(): nPos1 >= nPoints" );
868 	DBG_ASSERT( nP2 < mpImplPolygon->mnPoints,
869 				"Polygon::CalcDistance(): nPos2 >= nPoints" );
870 
871 	const Point& rP1 = mpImplPolygon->mpPointAry[ nP1 ];
872 	const Point& rP2 = mpImplPolygon->mpPointAry[ nP2 ];
873 	const double fDx = rP2.X() - rP1.X();
874 	const double fDy = rP2.Y() - rP1.Y();
875 
876 	return sqrt( fDx * fDx + fDy * fDy );
877 }
878 
879 // -----------------------------------------------------------------------
880 
881 void Polygon::Optimize( sal_uIntPtr nOptimizeFlags, const PolyOptimizeData* pData )
882 {
883 	DBG_CHKTHIS( Polygon, NULL );
884 	DBG_ASSERT( !mpImplPolygon->mpFlagAry, "Optimizing could fail with beziers!" );
885 
886 	sal_uInt16 nSize = mpImplPolygon->mnPoints;
887 
888 	if( nOptimizeFlags && nSize )
889 	{
890 		if( nOptimizeFlags & POLY_OPTIMIZE_EDGES )
891 		{
892 			const Rectangle	aBound( GetBoundRect() );
893 			const double	fArea = ( aBound.GetWidth() + aBound.GetHeight() ) * 0.5;
894 			const sal_uInt16	nPercent = pData ? pData->GetPercentValue() : 50;
895 
896 			Optimize( POLY_OPTIMIZE_NO_SAME );
897 			ImplReduceEdges( *this, fArea, nPercent );
898 		}
899 		else if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE | POLY_OPTIMIZE_NO_SAME ) )
900 		{
901 			Polygon			aNewPoly;
902 			const Point&	rFirst = mpImplPolygon->mpPointAry[ 0 ];
903 			sal_uIntPtr			nReduce;
904 
905 			if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE ) )
906 				nReduce = pData ? pData->GetAbsValue() : 4UL;
907 			else
908 				nReduce = 0UL;
909 
910 			while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
911 				nSize--;
912 
913 			if( nSize > 1 )
914 			{
915 				sal_uInt16 nLast = 0, nNewCount = 1;
916 
917 				aNewPoly.SetSize( nSize );
918 				aNewPoly[ 0 ] = rFirst;
919 
920 				for( sal_uInt16 i = 1; i < nSize; i++ )
921 				{
922 					if( ( mpImplPolygon->mpPointAry[ i ] != mpImplPolygon->mpPointAry[ nLast ] ) &&
923 						( !nReduce || ( nReduce < (sal_uIntPtr) FRound( CalcDistance( nLast, i ) ) ) ) )
924 					{
925 						aNewPoly[ nNewCount++ ] = mpImplPolygon->mpPointAry[ nLast = i ];
926 					}
927 				}
928 
929 				if( nNewCount == 1 )
930 					aNewPoly.Clear();
931 				else
932 					aNewPoly.SetSize( nNewCount );
933 			}
934 
935 			*this = aNewPoly;
936 		}
937 
938 		nSize = mpImplPolygon->mnPoints;
939 
940 		if( nSize > 1 )
941 		{
942 			if( ( nOptimizeFlags & POLY_OPTIMIZE_CLOSE ) &&
943 				( mpImplPolygon->mpPointAry[ 0 ] != mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
944 			{
945 				SetSize( mpImplPolygon->mnPoints + 1 );
946 				mpImplPolygon->mpPointAry[ mpImplPolygon->mnPoints - 1 ] = mpImplPolygon->mpPointAry[ 0 ];
947 			}
948 			else if( ( nOptimizeFlags & POLY_OPTIMIZE_OPEN ) &&
949 					 ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
950 			{
951 				const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
952 
953 				while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
954 					nSize--;
955 
956 				SetSize( nSize );
957 			}
958 		}
959 	}
960 }
961 
962 // =======================================================================
963 
964 /* Recursively subdivide cubic bezier curve via deCasteljau.
965 
966    @param rPointIter
967    Output iterator, where the subdivided polylines are written to.
968 
969    @param d
970    Squared difference of curve to a straight line
971 
972    @param P*
973    Exactly four points, interpreted as support and control points of
974    a cubic bezier curve. Must be in device coordinates, since stop
975    criterion is based on the following assumption: the device has a
976    finite resolution, it is thus sufficient to stop subdivision if the
977    curve does not deviate more than one pixel from a straight line.
978 
979 */
980 static void ImplAdaptiveSubdivide( ::std::back_insert_iterator< ::std::vector< Point > >& rPointIter,
981                                    const double old_d2,
982                                    int recursionDepth,
983                                    const double d2,
984                                    const double P1x, const double P1y,
985                                    const double P2x, const double P2y,
986                                    const double P3x, const double P3y,
987                                    const double P4x, const double P4y )
988 {
989     // Hard limit on recursion depth, empiric number.
990     enum {maxRecursionDepth=128};
991 
992     // Perform bezier flatness test (lecture notes from R. Schaback,
993     // Mathematics of Computer-Aided Design, Uni Goettingen, 2000)
994     //
995     // ||P(t) - L(t)|| <= max     ||b_j - b_0 - j/n(b_n - b_0)||
996     //                    0<=j<=n
997     //
998     // What is calculated here is an upper bound to the distance from
999     // a line through b_0 and b_3 (P1 and P4 in our notation) and the
1000     // curve. We can drop 0 and n from the running indices, since the
1001     // argument of max becomes zero for those cases.
1002     const double fJ1x( P2x - P1x - 1.0/3.0*(P4x - P1x) );
1003     const double fJ1y( P2y - P1y - 1.0/3.0*(P4y - P1y) );
1004     const double fJ2x( P3x - P1x - 2.0/3.0*(P4x - P1x) );
1005     const double fJ2y( P3y - P1y - 2.0/3.0*(P4y - P1y) );
1006     const double distance2( ::std::max( fJ1x*fJ1x + fJ1y*fJ1y,
1007                                         fJ2x*fJ2x + fJ2y*fJ2y) );
1008 
1009     // stop if error measure does not improve anymore. This is a
1010     // safety guard against floating point inaccuracies.
1011     // stop at recursion level 128. This is a safety guard against
1012     // floating point inaccuracies.
1013     // stop if distance from line is guaranteed to be bounded by d
1014     if( old_d2 > d2 &&
1015         recursionDepth < maxRecursionDepth &&
1016         distance2 >= d2 )
1017     {
1018         // deCasteljau bezier arc, split at t=0.5
1019         // Foley/vanDam, p. 508
1020         const double L1x( P1x ), 		   	 L1y( P1y );
1021         const double L2x( (P1x + P2x)*0.5 ), L2y( (P1y + P2y)*0.5 );
1022         const double Hx ( (P2x + P3x)*0.5 ), Hy ( (P2y + P3y)*0.5 );
1023         const double L3x( (L2x + Hx)*0.5 ),  L3y( (L2y + Hy)*0.5 );
1024         const double R4x( P4x ), 		   	 R4y( P4y );
1025         const double R3x( (P3x + P4x)*0.5 ), R3y( (P3y + P4y)*0.5 );
1026         const double R2x( (Hx + R3x)*0.5 ),  R2y( (Hy + R3y)*0.5 );
1027         const double R1x( (L3x + R2x)*0.5 ), R1y( (L3y + R2y)*0.5 );
1028         const double L4x( R1x ), 		     L4y( R1y );
1029 
1030 		// subdivide further
1031         ++recursionDepth;
1032         ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, L1x, L1y, L2x, L2y, L3x, L3y, L4x, L4y);
1033         ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, R1x, R1y, R2x, R2y, R3x, R3y, R4x, R4y);
1034     }
1035 	else
1036 	{
1037 		// requested resolution reached.
1038 		// Add end points to output iterator.
1039 		// order is preserved, since this is so to say depth first traversal.
1040 		*rPointIter++ = Point( FRound(P1x), FRound(P1y) );
1041 	}
1042 }
1043 
1044 // =======================================================================
1045 
1046 void Polygon::AdaptiveSubdivide( Polygon& rResult, const double d ) const
1047 {
1048 	if( !mpImplPolygon->mpFlagAry )
1049 	{
1050 		rResult = *this;
1051 	}
1052 	else
1053 	{
1054 		sal_uInt16 i;
1055 		sal_uInt16 nPts( GetSize() );
1056 		::std::vector< Point > aPoints;
1057         aPoints.reserve( nPts );
1058 		::std::back_insert_iterator< ::std::vector< Point > > aPointIter( aPoints );
1059 
1060 		for(i=0; i<nPts;)
1061 		{
1062 			if( ( i + 3 ) < nPts )
1063             {
1064                 sal_uInt8 P1( mpImplPolygon->mpFlagAry[ i ] );
1065                 sal_uInt8 P4( mpImplPolygon->mpFlagAry[ i + 3 ] );
1066 
1067                 if( ( POLY_NORMAL == P1 || POLY_SMOOTH == P1 || POLY_SYMMTR == P1 ) &&
1068                     ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 1 ] ) &&
1069                     ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 2 ] ) &&
1070                     ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
1071                 {
1072                     ImplAdaptiveSubdivide( aPointIter, d*d+1.0, 0, d*d,
1073                                            mpImplPolygon->mpPointAry[ i ].X(),   mpImplPolygon->mpPointAry[ i ].Y(),
1074                                            mpImplPolygon->mpPointAry[ i+1 ].X(), mpImplPolygon->mpPointAry[ i+1 ].Y(),
1075                                            mpImplPolygon->mpPointAry[ i+2 ].X(), mpImplPolygon->mpPointAry[ i+2 ].Y(),
1076                                            mpImplPolygon->mpPointAry[ i+3 ].X(), mpImplPolygon->mpPointAry[ i+3 ].Y() );
1077                     i += 3;
1078                     continue;
1079                 }
1080             }
1081 
1082             *aPointIter++ = mpImplPolygon->mpPointAry[ i++ ];
1083 		}
1084 
1085 		// fill result polygon
1086 		rResult = Polygon( (sal_uInt16)aPoints.size() ); // ensure sufficient size for copy
1087 		::std::copy(aPoints.begin(), aPoints.end(), rResult.mpImplPolygon->mpPointAry);
1088 	}
1089 }
1090 
1091 // -----------------------------------------------------------------------
1092 
1093 void Polygon::GetIntersection( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1094 {
1095 	const PolyPolygon aTmp( *this );
1096 	aTmp.GetIntersection( rPolyPoly, rResult );
1097 }
1098 
1099 // -----------------------------------------------------------------------
1100 
1101 void Polygon::GetUnion( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1102 {
1103 	const PolyPolygon aTmp( *this );
1104 	aTmp.GetUnion( rPolyPoly, rResult );
1105 }
1106 
1107 // -----------------------------------------------------------------------
1108 
1109 void Polygon::GetDifference( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1110 {
1111 	const PolyPolygon aTmp( *this );
1112 	aTmp.GetDifference( rPolyPoly, rResult );
1113 }
1114 
1115 // -----------------------------------------------------------------------
1116 
1117 void Polygon::GetXOR( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1118 {
1119 	const PolyPolygon aTmp( *this );
1120 	aTmp.GetXOR( rPolyPoly, rResult );
1121 }
1122 
1123 // -----------------------------------------------------------------------
1124 
1125 void Polygon::ImplReduceEdges( Polygon& rPoly, const double& rArea, sal_uInt16 nPercent )
1126 {
1127 	const double	fBound = 2000.0 * ( 100 - nPercent ) * 0.01;
1128 	sal_uInt16			nNumNoChange = 0, nNumRuns = 0;
1129 
1130 	while( nNumNoChange < 2 )
1131 	{
1132 		sal_uInt16	nPntCnt = rPoly.GetSize(), nNewPos = 0;
1133 		Polygon	aNewPoly( nPntCnt );
1134 		sal_Bool	bChangeInThisRun = sal_False;
1135 
1136 		for( sal_uInt16 n = 0; n < nPntCnt; n++ )
1137 		{
1138 			sal_Bool bDeletePoint = sal_False;
1139 
1140 			if( ( n + nNumRuns ) % 2 )
1141 			{
1142 				sal_uInt16		nIndPrev = !n ? nPntCnt - 1 : n - 1;
1143 				sal_uInt16		nIndPrevPrev = !nIndPrev ? nPntCnt - 1 : nIndPrev - 1;
1144 				sal_uInt16		nIndNext = ( n == nPntCnt-1 ) ? 0 : n + 1;
1145 				sal_uInt16		nIndNextNext = ( nIndNext == nPntCnt - 1 ) ? 0 : nIndNext + 1;
1146 				Vector2D	aVec1( rPoly[ nIndPrev ] ); aVec1 -= rPoly[ nIndPrevPrev ];
1147 				Vector2D	aVec2( rPoly[ n ] ); aVec2 -= rPoly[ nIndPrev ];
1148 				Vector2D	aVec3( rPoly[ nIndNext ] ); aVec3 -= rPoly[ n ];
1149 				Vector2D	aVec4( rPoly[ nIndNextNext ] ); aVec4 -= rPoly[ nIndNext ];
1150 				double		fDist1 = aVec1.GetLength(), fDist2 = aVec2.GetLength();
1151 				double		fDist3 = aVec3.GetLength(), fDist4 = aVec4.GetLength();
1152 				double		fTurnB = aVec2.Normalize().Scalar( aVec3.Normalize() );
1153 
1154 				if( fabs( fTurnB ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnB ) > ( 1.0 - SMALL_DVALUE ) )
1155 					bDeletePoint = sal_True;
1156 				else
1157 				{
1158 					Vector2D	aVecB( rPoly[ nIndNext ] );
1159 					double		fDistB = ( aVecB -= rPoly[ nIndPrev ] ).GetLength();
1160 					double		fLenWithB = fDist2 + fDist3;
1161 					double		fLenFact = ( fDistB != 0.0 ) ? fLenWithB / fDistB : 1.0;
1162 					double		fTurnPrev = aVec1.Normalize().Scalar( aVec2 );
1163 					double		fTurnNext = aVec3.Scalar( aVec4.Normalize() );
1164 					double		fGradPrev, fGradB, fGradNext;
1165 
1166 					if( fabs( fTurnPrev ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnPrev ) > ( 1.0 - SMALL_DVALUE ) )
1167 						fGradPrev = 0.0;
1168 					else
1169 						fGradPrev = acos( fTurnPrev ) / ( aVec1.IsNegative( aVec2 ) ? -F_PI180 : F_PI180 );
1170 
1171 					fGradB = acos( fTurnB ) / ( aVec2.IsNegative( aVec3 ) ? -F_PI180 : F_PI180 );
1172 
1173 					if( fabs( fTurnNext ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnNext ) > ( 1.0 - SMALL_DVALUE ) )
1174 						fGradNext = 0.0;
1175 					else
1176 						fGradNext = acos( fTurnNext ) / ( aVec3.IsNegative( aVec4 ) ? -F_PI180 : F_PI180 );
1177 
1178 					if( ( fGradPrev > 0.0 && fGradB < 0.0 && fGradNext > 0.0 ) ||
1179 						( fGradPrev < 0.0 && fGradB > 0.0 && fGradNext < 0.0 ) )
1180 					{
1181 						if( ( fLenFact < ( FSQRT2 + SMALL_DVALUE ) ) &&
1182 							( ( ( fDist1 + fDist4 ) / ( fDist2 + fDist3 ) ) * 2000.0 ) > fBound )
1183 						{
1184 							bDeletePoint = sal_True;
1185 						}
1186 					}
1187 					else
1188 					{
1189 						double fRelLen = 1.0 - sqrt( fDistB / rArea );
1190 
1191 						if( fRelLen < 0.0 )
1192 							fRelLen = 0.0;
1193 						else if( fRelLen > 1.0 )
1194 							fRelLen = 1.0;
1195 
1196 						if( ( (sal_uInt32) ( ( ( fLenFact - 1.0 ) * 1000000.0 ) + 0.5 ) < fBound ) &&
1197 							( fabs( fGradB ) <= ( fRelLen * fBound * 0.01 ) ) )
1198 						{
1199 							bDeletePoint = sal_True;
1200 						}
1201 					}
1202 				}
1203 			}
1204 
1205 			if( !bDeletePoint )
1206 				aNewPoly[ nNewPos++ ] = rPoly[ n ];
1207 			else
1208 				bChangeInThisRun = sal_True;
1209 		}
1210 
1211 		if( bChangeInThisRun && nNewPos )
1212 		{
1213 			aNewPoly.SetSize( nNewPos );
1214 			rPoly = aNewPoly;
1215 			nNumNoChange = 0;
1216 		}
1217 		else
1218 			nNumNoChange++;
1219 
1220 		nNumRuns++;
1221 	}
1222 }
1223 
1224 // -----------------------------------------------------------------------
1225 
1226 void Polygon::Move( long nHorzMove, long nVertMove )
1227 {
1228 	DBG_CHKTHIS( Polygon, NULL );
1229 
1230 	// Diese Abfrage sollte man fuer die DrawEngine durchfuehren
1231 	if ( !nHorzMove && !nVertMove )
1232 		return;
1233 
1234 	ImplMakeUnique();
1235 
1236 	// Punkte verschieben
1237 	sal_uInt16 nCount = mpImplPolygon->mnPoints;
1238 	for ( sal_uInt16 i = 0; i < nCount; i++ )
1239 	{
1240 		Point* pPt = &(mpImplPolygon->mpPointAry[i]);
1241 		pPt->X() += nHorzMove;
1242 		pPt->Y() += nVertMove;
1243 	}
1244 }
1245 
1246 // -----------------------------------------------------------------------
1247 
1248 void Polygon::Translate(const Point& rTrans)
1249 {
1250 	DBG_CHKTHIS( Polygon, NULL );
1251 	ImplMakeUnique();
1252 
1253 	for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1254 		mpImplPolygon->mpPointAry[ i ] += rTrans;
1255 }
1256 
1257 // -----------------------------------------------------------------------
1258 
1259 void Polygon::Scale( double fScaleX, double fScaleY )
1260 {
1261 	DBG_CHKTHIS( Polygon, NULL );
1262 	ImplMakeUnique();
1263 
1264 	for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1265 	{
1266 		Point& rPnt = mpImplPolygon->mpPointAry[i];
1267 		rPnt.X() = (long) ( fScaleX * rPnt.X() );
1268 		rPnt.Y() = (long) ( fScaleY * rPnt.Y() );
1269 	}
1270 }
1271 
1272 // -----------------------------------------------------------------------
1273 
1274 void Polygon::Rotate( const Point& rCenter, sal_uInt16 nAngle10 )
1275 {
1276 	DBG_CHKTHIS( Polygon, NULL );
1277 	nAngle10 %= 3600;
1278 
1279 	if( nAngle10 )
1280 	{
1281 		const double fAngle = F_PI1800 * nAngle10;
1282 		Rotate( rCenter, sin( fAngle ), cos( fAngle ) );
1283 	}
1284 }
1285 
1286 // -----------------------------------------------------------------------
1287 
1288 void Polygon::Rotate( const Point& rCenter, double fSin, double fCos )
1289 {
1290 	DBG_CHKTHIS( Polygon, NULL );
1291 	ImplMakeUnique();
1292 
1293 	long nX, nY;
1294 	long nCenterX = rCenter.X();
1295 	long nCenterY = rCenter.Y();
1296 
1297 	for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1298 	{
1299 		Point& rPt = mpImplPolygon->mpPointAry[ i ];
1300 
1301 		nX = rPt.X() - nCenterX;
1302 		nY = rPt.Y() - nCenterY;
1303 		rPt.X() = (long) FRound( fCos * nX + fSin * nY ) + nCenterX;
1304 		rPt.Y() = -(long) FRound( fSin * nX - fCos * nY ) + nCenterY;
1305 	}
1306 }
1307 
1308 // -----------------------------------------------------------------------
1309 
1310 void Polygon::SlantX( long nYRef, double fSin, double fCos )
1311 {
1312 	DBG_CHKTHIS( Polygon, NULL );
1313 	ImplMakeUnique();
1314 
1315 	for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1316 	{
1317 		Point&		rPnt = mpImplPolygon->mpPointAry[ i ];
1318 		const long	nDy = rPnt.Y() - nYRef;
1319 
1320 		rPnt.X() += (long)( fSin * nDy );
1321 		rPnt.Y() = nYRef + (long)( fCos * nDy );
1322 	}
1323 }
1324 
1325 // -----------------------------------------------------------------------
1326 
1327 void Polygon::SlantY( long nXRef, double fSin, double fCos )
1328 {
1329 	DBG_CHKTHIS( Polygon, NULL );
1330 	ImplMakeUnique();
1331 
1332 	for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1333 	{
1334 		Point&		rPnt = mpImplPolygon->mpPointAry[ i ];
1335 		const long	nDx = rPnt.X() - nXRef;
1336 
1337 		rPnt.X() = nXRef + (long)( fCos * nDx );
1338 		rPnt.Y() -= (long)( fSin * nDx );
1339 	}
1340 }
1341 
1342 // -----------------------------------------------------------------------
1343 
1344 void Polygon::Distort( const Rectangle& rRefRect, const Polygon& rDistortedRect )
1345 {
1346 	DBG_CHKTHIS( Polygon, NULL );
1347 	ImplMakeUnique();
1348 
1349 	long	Xr, Wr, X1, X2, X3, X4;
1350 	long	Yr, Hr, Y1, Y2, Y3, Y4;
1351 	double	fTx, fTy, fUx, fUy;
1352 
1353 	Xr = rRefRect.Left();
1354 	Yr = rRefRect.Top();
1355 	Wr = rRefRect.GetWidth();
1356 	Hr = rRefRect.GetHeight();
1357 
1358 	if( Wr && Hr )
1359 	{
1360 		DBG_ASSERT( rDistortedRect.mpImplPolygon->mnPoints >= 4, "Distort rect too small!" );
1361 
1362 		X1 = rDistortedRect[0].X();
1363 		Y1 = rDistortedRect[0].Y();
1364 		X2 = rDistortedRect[1].X();
1365 		Y2 = rDistortedRect[1].Y();
1366 		X3 = rDistortedRect[3].X();
1367 		Y3 = rDistortedRect[3].Y();
1368 		X4 = rDistortedRect[2].X();
1369 		Y4 = rDistortedRect[2].Y();
1370 
1371 		for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1372 		{
1373 			Point& rPnt = mpImplPolygon->mpPointAry[ i ];
1374 
1375 			fTx = (double)( rPnt.X() - Xr) / Wr;
1376 			fTy = (double)( rPnt.Y() - Yr) / Hr;
1377 			fUx = 1.0 - fTx;
1378 			fUy = 1.0 - fTy;
1379 
1380 			rPnt.X() = (long) ( fUy * (fUx * X1 + fTx * X2) + fTy * (fUx * X3 + fTx * X4) );
1381 			rPnt.Y() = (long) ( fUx * (fUy * Y1 + fTy * Y3) + fTx * (fUy * Y2 + fTy * Y4) );
1382 		}
1383 	}
1384 }
1385 
1386 // -----------------------------------------------------------------------
1387 
1388 class ImplPointFilter
1389 {
1390 public:
1391 	virtual void LastPoint() = 0;
1392 	virtual void Input( const Point& rPoint ) = 0;
1393 };
1394 
1395 class ImplPolygonPointFilter : public ImplPointFilter
1396 {
1397 public:
1398 	ImplPolygon*	mpPoly; 	// Nicht loeschen, wird dem Polygon zugewiesen
1399 	sal_uInt16			mnSize;
1400 
1401 					ImplPolygonPointFilter( sal_uInt16 nDestSize ) :
1402 						mnSize( 0 )
1403 					{
1404 						mpPoly = new ImplPolygon( nDestSize );
1405 					}
1406 
1407 	virtual void	LastPoint();
1408 	virtual void	Input( const Point& rPoint );
1409 };
1410 
1411 void ImplPolygonPointFilter::Input( const Point& rPoint )
1412 {
1413 	if ( !mnSize || (rPoint != mpPoly->mpPointAry[mnSize-1]) )
1414 	{
1415 		mnSize++;
1416 		if ( mnSize > mpPoly->mnPoints )
1417 			mpPoly->ImplSetSize( mnSize );
1418 		mpPoly->mpPointAry[mnSize-1] = rPoint;
1419 	}
1420 }
1421 
1422 void ImplPolygonPointFilter::LastPoint()
1423 {
1424 	if ( mnSize < mpPoly->mnPoints )
1425 		mpPoly->ImplSetSize( mnSize );
1426 };
1427 
1428 class ImplEdgePointFilter : public ImplPointFilter
1429 {
1430 	Point				maFirstPoint;
1431 	Point				maLastPoint;
1432 	ImplPointFilter&	mrNextFilter;
1433 	const long			mnLow;
1434 	const long			mnHigh;
1435 	const int			mnEdge;
1436 	int 				mnLastOutside;
1437 	sal_Bool				mbFirst;
1438 
1439 public:
1440 						ImplEdgePointFilter( int nEdge, long nLow, long nHigh,
1441 											 ImplPointFilter& rNextFilter ) :
1442 							mrNextFilter( rNextFilter ),
1443 							mnLow( nLow ),
1444 							mnHigh( nHigh ),
1445 							mnEdge( nEdge ),
1446 							mbFirst( sal_True )
1447 						{
1448 						}
1449 
1450 	Point				EdgeSection( const Point& rPoint, int nEdge ) const;
1451 	int 				VisibleSide( const Point& rPoint ) const;
1452 	int 				IsPolygon() const
1453 							{ return maFirstPoint == maLastPoint; }
1454 
1455 	virtual void		Input( const Point& rPoint );
1456 	virtual void		LastPoint();
1457 };
1458 
1459 inline int ImplEdgePointFilter::VisibleSide( const Point& rPoint ) const
1460 {
1461 	if ( mnEdge & EDGE_HORZ )
1462 	{
1463 		return rPoint.X() < mnLow ? EDGE_LEFT :
1464 									 rPoint.X() > mnHigh ? EDGE_RIGHT : 0;
1465 	}
1466 	else
1467 	{
1468 		return rPoint.Y() < mnLow ? EDGE_TOP :
1469 									 rPoint.Y() > mnHigh ? EDGE_BOTTOM : 0;
1470 	}
1471 }
1472 
1473 Point ImplEdgePointFilter::EdgeSection( const Point& rPoint, int nEdge ) const
1474 {
1475 	long lx = maLastPoint.X();
1476 	long ly = maLastPoint.Y();
1477 	long md = rPoint.X() - lx;
1478 	long mn = rPoint.Y() - ly;
1479 	long nNewX;
1480 	long nNewY;
1481 
1482 	if ( nEdge & EDGE_VERT )
1483 	{
1484 		nNewY = (nEdge == EDGE_TOP) ? mnLow : mnHigh;
1485 		long dy = nNewY - ly;
1486 		if ( !md )
1487 			nNewX = lx;
1488 		else if ( (LONG_MAX / Abs(md)) >= Abs(dy) )
1489 			nNewX = (dy * md) / mn + lx;
1490 		else
1491 		{
1492 			BigInt ady = dy;
1493 			ady *= md;
1494 			if( ady.IsNeg() )
1495 				if( mn < 0 )
1496 					ady += mn/2;
1497 				else
1498 					ady -= (mn-1)/2;
1499 			else
1500 				if( mn < 0 )
1501 					ady -= (mn+1)/2;
1502 				else
1503 					ady += mn/2;
1504 			ady /= mn;
1505 			nNewX = (long)ady + lx;
1506 		}
1507 	}
1508 	else
1509 	{
1510 		nNewX = (nEdge == EDGE_LEFT) ? mnLow : mnHigh;
1511 		long dx = nNewX - lx;
1512 		if ( !mn )
1513 			nNewY = ly;
1514 		else if ( (LONG_MAX / Abs(mn)) >= Abs(dx) )
1515 			nNewY = (dx * mn) / md + ly;
1516 		else
1517 		{
1518 			BigInt adx = dx;
1519 			adx *= mn;
1520 			if( adx.IsNeg() )
1521 				if( md < 0 )
1522 					adx += md/2;
1523 				else
1524 					adx -= (md-1)/2;
1525 			else
1526 				if( md < 0 )
1527 					adx -= (md+1)/2;
1528 				else
1529 					adx += md/2;
1530 			adx /= md;
1531 			nNewY = (long)adx + ly;
1532 		}
1533 	}
1534 
1535 	return Point( nNewX, nNewY );
1536 }
1537 
1538 void ImplEdgePointFilter::Input( const Point& rPoint )
1539 {
1540 	int nOutside = VisibleSide( rPoint );
1541 
1542 	if ( mbFirst )
1543 	{
1544 		maFirstPoint = rPoint;
1545 		mbFirst 	 = sal_False;
1546 		if ( !nOutside )
1547 			mrNextFilter.Input( rPoint );
1548 	}
1549 	else if ( rPoint == maLastPoint )
1550 		return;
1551 	else if ( !nOutside )
1552 	{
1553 		if ( mnLastOutside )
1554 			mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1555 		mrNextFilter.Input( rPoint );
1556 	}
1557 	else if ( !mnLastOutside )
1558 		mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1559 	else if ( nOutside != mnLastOutside )
1560 	{
1561 		mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1562 		mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1563 	}
1564 
1565 	maLastPoint    = rPoint;
1566 	mnLastOutside  = nOutside;
1567 }
1568 
1569 void ImplEdgePointFilter::LastPoint()
1570 {
1571 	if ( !mbFirst )
1572 	{
1573 		int nOutside = VisibleSide( maFirstPoint );
1574 
1575 		if ( nOutside != mnLastOutside )
1576 			Input( maFirstPoint );
1577 		mrNextFilter.LastPoint();
1578 	}
1579 }
1580 
1581 // -----------------------------------------------------------------------
1582 
1583 void Polygon::Clip( const Rectangle& rRect, sal_Bool bPolygon )
1584 {
1585     // #105251# Justify rect befor edge filtering
1586     Rectangle				aJustifiedRect( rRect );
1587     aJustifiedRect.Justify();
1588 
1589 	sal_uInt16					nSourceSize = mpImplPolygon->mnPoints;
1590 	ImplPolygonPointFilter	aPolygon( nSourceSize );
1591 	ImplEdgePointFilter 	aHorzFilter( EDGE_HORZ, aJustifiedRect.Left(), aJustifiedRect.Right(),
1592 										 aPolygon );
1593 	ImplEdgePointFilter 	aVertFilter( EDGE_VERT, aJustifiedRect.Top(), aJustifiedRect.Bottom(),
1594 										 aHorzFilter );
1595 
1596 	for ( sal_uInt16 i = 0; i < nSourceSize; i++ )
1597 		aVertFilter.Input( mpImplPolygon->mpPointAry[i] );
1598 	if ( bPolygon || aVertFilter.IsPolygon() )
1599 		aVertFilter.LastPoint();
1600 	else
1601 		aPolygon.LastPoint();
1602 
1603 	// Alte ImpPolygon-Daten loeschen und die vom ImpPolygonPointFilter
1604 	// zuweisen
1605 	if ( mpImplPolygon->mnRefCount )
1606 	{
1607 		if ( mpImplPolygon->mnRefCount > 1 )
1608 			mpImplPolygon->mnRefCount--;
1609 		else
1610 			delete mpImplPolygon;
1611 	}
1612 	mpImplPolygon = aPolygon.mpPoly;
1613 }
1614 
1615 // -----------------------------------------------------------------------
1616 
1617 Rectangle Polygon::GetBoundRect() const
1618 {
1619 	DBG_CHKTHIS( Polygon, NULL );
1620     // Removing the assert. Bezier curves have the attribute that each single
1621     // curve segment defined by four points can not exit the four-point polygon
1622     // defined by that points. This allows to say that the curve segment can also
1623     // never leave the Range of it's defining points.
1624     // The result is that Polygon::GetBoundRect() may not create the minimal
1625     // BoundRect of the Polygon (to get that, use basegfx::B2DPolygon classes),
1626     // but will always create a valid BoundRect, at least as long as this method
1627     // 'blindly' travels over all points, including control points.
1628     //
1629 	// DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetBoundRect could fail with beziers!" );
1630 
1631 	sal_uInt16	nCount = mpImplPolygon->mnPoints;
1632 	if( ! nCount )
1633 		return Rectangle();
1634 
1635 	long	nXMin, nXMax, nYMin, nYMax;
1636 
1637 	const Point* pPt = &(mpImplPolygon->mpPointAry[0]);
1638 	nXMin = nXMax = pPt->X();
1639 	nYMin = nYMax = pPt->Y();
1640 
1641 	for ( sal_uInt16 i = 0; i < nCount; i++ )
1642 	{
1643 		pPt = &(mpImplPolygon->mpPointAry[i]);
1644 
1645 		if ( pPt->X() < nXMin )
1646 			nXMin = pPt->X();
1647 		if ( pPt->X() > nXMax )
1648 			nXMax = pPt->X();
1649 		if ( pPt->Y() < nYMin )
1650 			nYMin = pPt->Y();
1651 		if ( pPt->Y() > nYMax )
1652 			nYMax = pPt->Y();
1653 	}
1654 
1655 	return Rectangle( nXMin, nYMin, nXMax, nYMax );
1656 }
1657 
1658 // -----------------------------------------------------------------------
1659 
1660 double Polygon::GetArea() const
1661 {
1662 	const double fArea = GetSignedArea();
1663 	return( ( fArea < 0.0 ) ? -fArea : fArea );
1664 }
1665 
1666 // -----------------------------------------------------------------------
1667 
1668 double Polygon::GetSignedArea() const
1669 {
1670 	DBG_CHKTHIS( Polygon, NULL );
1671 	DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetArea could fail with beziers!" );
1672 
1673 	double fArea = 0.0;
1674 
1675 	if( mpImplPolygon->mnPoints > 2 )
1676 	{
1677 		const sal_uInt16 nCount1 = mpImplPolygon->mnPoints - 1;
1678 
1679 		for( sal_uInt16 i = 0; i < nCount1; )
1680 		{
1681 			const Point& rPt = mpImplPolygon->mpPointAry[ i ];
1682 			const Point& rPt1 = mpImplPolygon->mpPointAry[ ++i ];
1683 			fArea += ( rPt.X() - rPt1.X() ) * ( rPt.Y() + rPt1.Y() );
1684 		}
1685 
1686 		const Point& rPt = mpImplPolygon->mpPointAry[ nCount1 ];
1687 		const Point& rPt0 = mpImplPolygon->mpPointAry[ 0 ];
1688 		fArea += ( rPt.X() - rPt0.X() ) * ( rPt.Y() + rPt0.Y() );
1689 	}
1690 
1691 	return fArea;
1692 }
1693 
1694 // -----------------------------------------------------------------------
1695 
1696 sal_Bool Polygon::IsInside( const Point& rPoint ) const
1697 {
1698 	DBG_CHKTHIS( Polygon, NULL );
1699 	DBG_ASSERT( !mpImplPolygon->mpFlagAry, "IsInside could fail with beziers!" );
1700 
1701 	const Rectangle aBound( GetBoundRect() );
1702 	const Line		aLine( rPoint, Point( aBound.Right() + 100L, rPoint.Y() ) );
1703 	sal_uInt16			nCount = mpImplPolygon->mnPoints;
1704 	sal_uInt16			nPCounter = 0;
1705 
1706 	if ( ( nCount > 2 ) && aBound.IsInside( rPoint ) )
1707 	{
1708 		Point	aPt1( mpImplPolygon->mpPointAry[ 0 ] );
1709 		Point	aIntersection;
1710 		Point	aLastIntersection;
1711 
1712 		while ( ( aPt1 == mpImplPolygon->mpPointAry[ nCount - 1 ] ) && ( nCount > 3 ) )
1713 			nCount--;
1714 
1715 		for ( sal_uInt16 i = 1; i <= nCount; i++ )
1716 		{
1717 			const Point& rPt2 = mpImplPolygon->mpPointAry[ ( i < nCount ) ? i : 0 ];
1718 
1719 			if ( aLine.Intersection( Line( aPt1, rPt2 ), aIntersection ) )
1720 			{
1721 				// Hiermit verhindern wir das Einfuegen von
1722 				// doppelten Intersections, die gleich hintereinander folgen
1723 				if ( nPCounter )
1724 				{
1725 					if ( aIntersection != aLastIntersection )
1726 					{
1727 						aLastIntersection = aIntersection;
1728 						nPCounter++;
1729 					}
1730 				}
1731 				else
1732 				{
1733 					aLastIntersection = aIntersection;
1734 					nPCounter++;
1735 				}
1736 			}
1737 
1738 			aPt1 = rPt2;
1739 		}
1740 	}
1741 
1742 	// innerhalb, wenn die Anzahl der Schnittpunkte ungerade ist
1743 	return ( ( nPCounter & 1 ) == 1 );
1744 }
1745 
1746 // -----------------------------------------------------------------------
1747 
1748 sal_Bool Polygon::IsRightOrientated() const
1749 {
1750 	DBG_CHKTHIS( Polygon, NULL );
1751 	return GetSignedArea() >= 0.0;
1752 }
1753 
1754 // -----------------------------------------------------------------------
1755 
1756 void Polygon::Insert( sal_uInt16 nPos, const Point& rPt, PolyFlags eFlags )
1757 {
1758 	DBG_CHKTHIS( Polygon, NULL );
1759 	ImplMakeUnique();
1760 
1761 	if( nPos >= mpImplPolygon->mnPoints )
1762 		nPos = mpImplPolygon->mnPoints;
1763 
1764 	mpImplPolygon->ImplSplit( nPos, 1 );
1765 	mpImplPolygon->mpPointAry[ nPos ] = rPt;
1766 
1767 	if( POLY_NORMAL != eFlags )
1768 	{
1769 		mpImplPolygon->ImplCreateFlagArray();
1770 		mpImplPolygon->mpFlagAry[ nPos ] = (sal_uInt8) eFlags;
1771 	}
1772 }
1773 
1774 // -----------------------------------------------------------------------
1775 
1776 void Polygon::Insert( sal_uInt16 nPos, const Polygon& rPoly )
1777 {
1778 	DBG_CHKTHIS( Polygon, NULL );
1779 	const sal_uInt16 nInsertCount = rPoly.mpImplPolygon->mnPoints;
1780 
1781 	if( nInsertCount )
1782 	{
1783 		ImplMakeUnique();
1784 
1785 		if( nPos >= mpImplPolygon->mnPoints )
1786 			nPos = mpImplPolygon->mnPoints;
1787 
1788 		if( rPoly.mpImplPolygon->mpFlagAry )
1789 			mpImplPolygon->ImplCreateFlagArray();
1790 
1791 		mpImplPolygon->ImplSplit( nPos, nInsertCount, rPoly.mpImplPolygon );
1792 	}
1793 }
1794 
1795 // -----------------------------------------------------------------------
1796 
1797 void Polygon::Remove( sal_uInt16 nPos, sal_uInt16 nCount )
1798 {
1799 	DBG_CHKTHIS( Polygon, NULL );
1800 	if( nCount && ( nPos < mpImplPolygon->mnPoints ) )
1801 	{
1802 		ImplMakeUnique();
1803 		mpImplPolygon->ImplRemove( nPos, nCount );
1804 	}
1805 }
1806 
1807 // -----------------------------------------------------------------------
1808 
1809 Point& Polygon::operator[]( sal_uInt16 nPos )
1810 {
1811 	DBG_CHKTHIS( Polygon, NULL );
1812 	DBG_ASSERT( nPos < mpImplPolygon->mnPoints, "Polygon::[]: nPos >= nPoints" );
1813 
1814 	ImplMakeUnique();
1815 	return mpImplPolygon->mpPointAry[nPos];
1816 }
1817 
1818 // -----------------------------------------------------------------------
1819 
1820 Polygon& Polygon::operator=( const Polygon& rPoly )
1821 {
1822 	DBG_CHKTHIS( Polygon, NULL );
1823 	DBG_CHKOBJ( &rPoly, Polygon, NULL );
1824 	DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
1825 
1826 	// Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
1827 	// RefCount == 0 fuer statische Objekte
1828 	if ( rPoly.mpImplPolygon->mnRefCount )
1829 		rPoly.mpImplPolygon->mnRefCount++;
1830 
1831 	// Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
1832 	// die letzte Referenz ist, sonst Referenzcounter decrementieren
1833 	if ( mpImplPolygon->mnRefCount )
1834 	{
1835 		if ( mpImplPolygon->mnRefCount > 1 )
1836 			mpImplPolygon->mnRefCount--;
1837 		else
1838 			delete mpImplPolygon;
1839 	}
1840 
1841 	mpImplPolygon = rPoly.mpImplPolygon;
1842 	return *this;
1843 }
1844 
1845 // -----------------------------------------------------------------------
1846 
1847 sal_Bool Polygon::operator==( const Polygon& rPoly ) const
1848 {
1849 	DBG_CHKTHIS( Polygon, NULL );
1850 	DBG_CHKOBJ( &rPoly, Polygon, NULL );
1851 
1852 	if ( (rPoly.mpImplPolygon == mpImplPolygon) )
1853 		return sal_True;
1854 	else
1855 		return sal_False;
1856 }
1857 
1858 // -----------------------------------------------------------------------
1859 
1860 sal_Bool Polygon::IsEqual( const Polygon& rPoly ) const
1861 {
1862 	sal_Bool bIsEqual = sal_True;;
1863 	sal_uInt16 i;
1864 	if ( GetSize() != rPoly.GetSize() )
1865 		bIsEqual = sal_False;
1866 	else
1867 	{
1868 		for ( i = 0; i < GetSize(); i++ )
1869 		{
1870 			if ( ( GetPoint( i ) != rPoly.GetPoint( i ) ) ||
1871 				( GetFlags( i ) != rPoly.GetFlags( i ) ) )
1872 			{
1873 				bIsEqual = sal_False;
1874 				break;
1875 			}
1876 		}
1877 	}
1878 	return bIsEqual;
1879 }
1880 
1881 // -----------------------------------------------------------------------
1882 
1883 SvStream& operator>>( SvStream& rIStream, Polygon& rPoly )
1884 {
1885 	DBG_CHKOBJ( &rPoly, Polygon, NULL );
1886 	DBG_ASSERTWARNING( rIStream.GetVersion(), "Polygon::>> - Solar-Version not set on rIStream" );
1887 
1888 	sal_uInt16			i;
1889 	sal_uInt16			nStart;
1890 	sal_uInt16			nCurPoints;
1891 	sal_uInt16			nPoints;
1892 	unsigned char	bShort;
1893 	short			nShortX;
1894 	short			nShortY;
1895 	long			nLongX;
1896 	long			nLongY;
1897 
1898 	// Anzahl der Punkte einlesen und Array erzeugen
1899 	rIStream >> nPoints;
1900 	if ( rPoly.mpImplPolygon->mnRefCount != 1 )
1901 	{
1902 		if ( rPoly.mpImplPolygon->mnRefCount )
1903 			rPoly.mpImplPolygon->mnRefCount--;
1904 		rPoly.mpImplPolygon = new ImplPolygon( nPoints );
1905 	}
1906 	else
1907 		rPoly.mpImplPolygon->ImplSetSize( nPoints, sal_False );
1908 
1909 	// Je nach CompressMode das Polygon einlesen
1910 	if ( rIStream.GetCompressMode() == COMPRESSMODE_FULL )
1911 	{
1912 		i = 0;
1913 		while ( i < nPoints )
1914 		{
1915 			rIStream >> bShort >> nCurPoints;
1916 
1917 			if ( bShort )
1918 			{
1919 				for ( nStart = i; i < nStart+nCurPoints; i++ )
1920 				{
1921 					rIStream >> nShortX >> nShortY;
1922 					rPoly.mpImplPolygon->mpPointAry[i].X() = nShortX;
1923 					rPoly.mpImplPolygon->mpPointAry[i].Y() = nShortY;
1924 				}
1925 			}
1926 			else
1927 			{
1928 				for ( nStart = i; i < nStart+nCurPoints; i++ )
1929 				{
1930 					rIStream >> nLongX >> nLongY;
1931 					rPoly.mpImplPolygon->mpPointAry[i].X() = nLongX;
1932 					rPoly.mpImplPolygon->mpPointAry[i].Y() = nLongY;
1933 				}
1934 			}
1935 		}
1936 	}
1937 	else
1938 	{
1939 		// Feststellen, ob ueber die Operatoren geschrieben werden muss
1940 #if (SAL_TYPES_SIZEOFLONG) != 4
1941 		if ( 1 )
1942 #else
1943 #ifdef OSL_BIGENDIAN
1944 		if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
1945 #else
1946 		if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
1947 #endif
1948 #endif
1949 		{
1950 			for( i = 0; i < nPoints; i++ )
1951 			{
1952 				rIStream >> rPoly.mpImplPolygon->mpPointAry[i].X()
1953 						 >> rPoly.mpImplPolygon->mpPointAry[i].Y();
1954 			}
1955 		}
1956 		else
1957 			rIStream.Read( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
1958 	}
1959 
1960 	return rIStream;
1961 }
1962 
1963 // -----------------------------------------------------------------------
1964 
1965 SvStream& operator<<( SvStream& rOStream, const Polygon& rPoly )
1966 {
1967 	DBG_CHKOBJ( &rPoly, Polygon, NULL );
1968 	DBG_ASSERTWARNING( rOStream.GetVersion(), "Polygon::<< - Solar-Version not set on rOStream" );
1969 
1970 	unsigned char	bShort;
1971 	unsigned char	bCurShort;
1972 	sal_uInt16			nStart;
1973 	sal_uInt16			i;
1974 	sal_uInt16			nPoints = rPoly.GetSize();
1975 
1976 	// Anzahl der Punkte rausschreiben
1977 	rOStream << nPoints;
1978 
1979 	// Je nach CompressMode das Polygon rausschreiben
1980 	if ( rOStream.GetCompressMode() == COMPRESSMODE_FULL )
1981 	{
1982 		i = 0;
1983 		while ( i < nPoints )
1984 		{
1985 			nStart = i;
1986 
1987 			// Feststellen, welcher Typ geschrieben werden soll
1988 			if ( ((rPoly.mpImplPolygon->mpPointAry[nStart].X() >= SHRT_MIN) &&
1989 				  (rPoly.mpImplPolygon->mpPointAry[nStart].X() <= SHRT_MAX)) &&
1990 				 ((rPoly.mpImplPolygon->mpPointAry[nStart].Y() >= SHRT_MIN) &&
1991 				  (rPoly.mpImplPolygon->mpPointAry[nStart].Y() <= SHRT_MAX)) )
1992 				bShort = sal_True;
1993 			else
1994 				bShort = sal_False;
1995 			while ( i < nPoints )
1996 			{
1997 				// Feststellen, welcher Typ geschrieben werden soll
1998 				if ( ((rPoly.mpImplPolygon->mpPointAry[nStart].X() >= SHRT_MIN) &&
1999 					  (rPoly.mpImplPolygon->mpPointAry[nStart].X() <= SHRT_MAX)) &&
2000 					 ((rPoly.mpImplPolygon->mpPointAry[nStart].Y() >= SHRT_MIN) &&
2001 					  (rPoly.mpImplPolygon->mpPointAry[nStart].Y() <= SHRT_MAX)) )
2002 					bCurShort = sal_True;
2003 				else
2004 					bCurShort = sal_False;
2005 
2006 				// Wenn sich die Werte in einen anderen Bereich begeben,
2007 				// muessen wir neu rausschreiben
2008 				if ( bCurShort != bShort )
2009 				{
2010 					bShort = bCurShort;
2011 					break;
2012 				}
2013 
2014 				i++;
2015 			}
2016 
2017 			rOStream << bShort << (sal_uInt16)(i-nStart);
2018 
2019 			if ( bShort )
2020 			{
2021 				for( ; nStart < i; nStart++ )
2022 				{
2023 					rOStream << (short)rPoly.mpImplPolygon->mpPointAry[nStart].X()
2024 							 << (short)rPoly.mpImplPolygon->mpPointAry[nStart].Y();
2025 				}
2026 			}
2027 			else
2028 			{
2029 				for( ; nStart < i; nStart++ )
2030 				{
2031 					rOStream << rPoly.mpImplPolygon->mpPointAry[nStart].X()
2032 							 << rPoly.mpImplPolygon->mpPointAry[nStart].Y();
2033 				}
2034 			}
2035 		}
2036 	}
2037 	else
2038 	{
2039 		// Feststellen, ob ueber die Operatoren geschrieben werden muss
2040 #if (SAL_TYPES_SIZEOFLONG) != 4
2041 		if ( 1 )
2042 #else
2043 #ifdef OSL_BIGENDIAN
2044 		if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
2045 #else
2046 		if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
2047 #endif
2048 #endif
2049 		{
2050 			for( i = 0; i < nPoints; i++ )
2051 			{
2052 				rOStream << rPoly.mpImplPolygon->mpPointAry[i].X()
2053 						 << rPoly.mpImplPolygon->mpPointAry[i].Y();
2054 			}
2055 		}
2056 		else
2057 		{
2058 			if ( nPoints )
2059 				rOStream.Write( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
2060 		}
2061 	}
2062 
2063 	return rOStream;
2064 }
2065 
2066 // -----------------------------------------------------------------------
2067 
2068 void Polygon::ImplRead( SvStream& rIStream )
2069 {
2070 	sal_uInt8	bHasPolyFlags;
2071 
2072 	rIStream >> *this
2073 			 >> bHasPolyFlags;
2074 
2075 	if ( bHasPolyFlags )
2076 	{
2077 		mpImplPolygon->mpFlagAry = new sal_uInt8[ mpImplPolygon->mnPoints ];
2078 		rIStream.Read( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
2079 	}
2080 }
2081 
2082 // -----------------------------------------------------------------------
2083 
2084 void Polygon::Read( SvStream& rIStream )
2085 {
2086 	VersionCompat aCompat( rIStream, STREAM_READ );
2087 
2088     ImplRead( rIStream );
2089 }
2090 
2091 // -----------------------------------------------------------------------
2092 
2093 void Polygon::ImplWrite( SvStream& rOStream ) const
2094 {
2095 	sal_uInt8	bHasPolyFlags = mpImplPolygon->mpFlagAry != NULL;
2096 	rOStream << *this
2097 			 << bHasPolyFlags;
2098 
2099 	if ( bHasPolyFlags )
2100 		rOStream.Write( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
2101 }
2102 
2103 // -----------------------------------------------------------------------
2104 
2105 void Polygon::Write( SvStream& rOStream ) const
2106 {
2107 	VersionCompat aCompat( rOStream, STREAM_WRITE, 1 );
2108 
2109     ImplWrite( rOStream );
2110 }
2111 
2112 // -----------------------------------------------------------------------
2113 // #i74631# numerical correction method for B2DPolygon
2114 void impCorrectContinuity(basegfx::B2DPolygon& roPolygon, sal_uInt32 nIndex, sal_uInt8 nCFlag)
2115 {
2116 	const sal_uInt32 nPointCount(roPolygon.count());
2117 	OSL_ENSURE(nIndex < nPointCount, "impCorrectContinuity: index access out of range (!)");
2118 
2119 	if(nIndex < nPointCount && (POLY_SMOOTH == nCFlag || POLY_SYMMTR == nCFlag))
2120 	{
2121 		if(roPolygon.isPrevControlPointUsed(nIndex) && roPolygon.isNextControlPointUsed(nIndex))
2122 		{
2123 			const basegfx::B2DPoint aPoint(roPolygon.getB2DPoint(nIndex));
2124 
2125 			if(POLY_SMOOTH == nCFlag)
2126 			{
2127 				// C1: apply inverse direction of prev to next, keep length of next
2128 				const basegfx::B2DVector aOriginalNext(roPolygon.getNextControlPoint(nIndex) - aPoint);
2129 				basegfx::B2DVector aNewNext(aPoint - roPolygon.getPrevControlPoint(nIndex));
2130 
2131 				aNewNext.setLength(aOriginalNext.getLength());
2132 				roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + aNewNext));
2133 			}
2134 			else // POLY_SYMMTR
2135 			{
2136 				// C2: apply inverse control point to next
2137 				roPolygon.setNextControlPoint(nIndex, (2.0 * aPoint) - roPolygon.getPrevControlPoint(nIndex));
2138 			}
2139 		}
2140 	}
2141 }
2142 
2143 // -----------------------------------------------------------------------
2144 // convert to basegfx::B2DPolygon and return
2145 basegfx::B2DPolygon Polygon::getB2DPolygon() const
2146 {
2147 	basegfx::B2DPolygon aRetval;
2148 	const sal_uInt16 nCount(mpImplPolygon->mnPoints);
2149 
2150 	if(nCount)
2151 	{
2152 		if(mpImplPolygon->mpFlagAry)
2153 		{
2154 			// handling for curves. Add start point
2155 			const Point aStartPoint(mpImplPolygon->mpPointAry[0]);
2156 			sal_uInt8 nPointFlag(mpImplPolygon->mpFlagAry[0]);
2157 			aRetval.append(basegfx::B2DPoint(aStartPoint.X(), aStartPoint.Y()));
2158 			Point aControlA, aControlB;
2159 
2160 			for(sal_uInt16 a(1); a < nCount;)
2161 			{
2162 				bool bControlA(false);
2163 				bool bControlB(false);
2164 
2165 				if(POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
2166 				{
2167 					aControlA = mpImplPolygon->mpPointAry[a++];
2168 					bControlA = true;
2169 				}
2170 
2171 				if(a < nCount && POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
2172 				{
2173 					aControlB = mpImplPolygon->mpPointAry[a++];
2174 					bControlB = true;
2175 				}
2176 
2177 				// assert invalid polygons
2178 				OSL_ENSURE(bControlA == bControlB, "Polygon::getB2DPolygon: Invalid source polygon (!)");
2179 
2180 				if(a < nCount)
2181 				{
2182 					const Point aEndPoint(mpImplPolygon->mpPointAry[a]);
2183 
2184 					if(bControlA)
2185 					{
2186 						// bezier edge, add
2187 						aRetval.appendBezierSegment(
2188 							basegfx::B2DPoint(aControlA.X(), aControlA.Y()),
2189 							basegfx::B2DPoint(aControlB.X(), aControlB.Y()),
2190 							basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
2191 
2192 						impCorrectContinuity(aRetval, aRetval.count() - 2, nPointFlag);
2193 					}
2194 					else
2195 					{
2196 						// no bezier edge, add end point
2197 						aRetval.append(basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
2198 					}
2199 
2200 					nPointFlag = mpImplPolygon->mpFlagAry[a++];
2201 				}
2202 			}
2203 
2204 			// if exist, remove double first/last points, set closed and correct control points
2205 			basegfx::tools::checkClosed(aRetval);
2206 
2207 			if(aRetval.isClosed())
2208 			{
2209 				// closeWithGeometryChange did really close, so last point(s) were removed.
2210 				// Correct the continuity in the changed point
2211 				impCorrectContinuity(aRetval, 0, mpImplPolygon->mpFlagAry[0]);
2212 			}
2213 		}
2214 		else
2215 		{
2216 			// extra handling for non-curves (most-used case) for speedup
2217 			for(sal_uInt16 a(0); a < nCount; a++)
2218 			{
2219 				// get point and add
2220 				const Point aPoint(mpImplPolygon->mpPointAry[a]);
2221 				aRetval.append(basegfx::B2DPoint(aPoint.X(), aPoint.Y()));
2222 			}
2223 
2224 			// set closed flag
2225 			basegfx::tools::checkClosed(aRetval);
2226 		}
2227 	}
2228 
2229 	return aRetval;
2230 }
2231 
2232 // -----------------------------------------------------------------------
2233 // constructor to convert from basegfx::B2DPolygon
2234 // #i76891# Needed to change from adding all control points (even for unused
2235 // edges) and creating a fixed-size Polygon in the first run to creating the
2236 // minimal Polygon. This requires a temporary Point- and Flag-Array for curves
2237 // and a memcopy at ImplPolygon creation, but contains no zero-controlpoints
2238 // for straight edges.
2239 Polygon::Polygon(const basegfx::B2DPolygon& rPolygon)
2240 :	mpImplPolygon(0)
2241 {
2242 	DBG_CTOR( Polygon, NULL );
2243 
2244 	const bool bCurve(rPolygon.areControlPointsUsed());
2245 	const bool bClosed(rPolygon.isClosed());
2246 	sal_uInt32 nB2DLocalCount(rPolygon.count());
2247 
2248 	if(bCurve)
2249 	{
2250 		// #127979# Reduce source point count hard to the limit of the tools Polygon
2251 		if(nB2DLocalCount > ((0x0000ffff / 3L) - 1L))
2252 		{
2253 			DBG_ERROR("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
2254 			nB2DLocalCount = ((0x0000ffff / 3L) - 1L);
2255 		}
2256 
2257 		// calculate target point count
2258 		const sal_uInt32 nLoopCount(bClosed ? nB2DLocalCount : (nB2DLocalCount ? nB2DLocalCount - 1L : 0L ));
2259 
2260 		if(nLoopCount)
2261 		{
2262 			// calculate maximum array size and allocate; prepare insert index
2263 			const sal_uInt32 nMaxTargetCount((nLoopCount * 3) + 1);
2264 			mpImplPolygon = new ImplPolygon(static_cast< sal_uInt16 >(nMaxTargetCount), true);
2265 
2266 			// prepare insert index and current point
2267 			sal_uInt32 nArrayInsert(0);
2268 			basegfx::B2DCubicBezier aBezier;
2269 			aBezier.setStartPoint(rPolygon.getB2DPoint(0));
2270 
2271 			for(sal_uInt32 a(0L); a < nLoopCount; a++)
2272 			{
2273 				// add current point (always) and remember StartPointIndex for evtl. later corrections
2274 				const Point aStartPoint(FRound(aBezier.getStartPoint().getX()), FRound(aBezier.getStartPoint().getY()));
2275 				const sal_uInt32 nStartPointIndex(nArrayInsert);
2276 				mpImplPolygon->mpPointAry[nStartPointIndex] = aStartPoint;
2277 				mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_NORMAL;
2278 				nArrayInsert++;
2279 
2280 				// prepare next segment
2281 				const sal_uInt32 nNextIndex((a + 1) % nB2DLocalCount);
2282 				aBezier.setEndPoint(rPolygon.getB2DPoint(nNextIndex));
2283 				aBezier.setControlPointA(rPolygon.getNextControlPoint(a));
2284 				aBezier.setControlPointB(rPolygon.getPrevControlPoint(nNextIndex));
2285 
2286 				if(aBezier.isBezier())
2287 				{
2288 					// if one is used, add always two control points due to the old schema
2289 					mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointA().getX()), FRound(aBezier.getControlPointA().getY()));
2290 					mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
2291 					nArrayInsert++;
2292 
2293 					mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointB().getX()), FRound(aBezier.getControlPointB().getY()));
2294 					mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
2295 					nArrayInsert++;
2296 				}
2297 
2298 				// test continuity with previous control point to set flag value
2299 				if(aBezier.getControlPointA() != aBezier.getStartPoint() && (bClosed || a))
2300 				{
2301 					const basegfx::B2VectorContinuity eCont(rPolygon.getContinuityInPoint(a));
2302 
2303 					if(basegfx::CONTINUITY_C1 == eCont)
2304 					{
2305 						mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SMOOTH;
2306 					}
2307 					else if(basegfx::CONTINUITY_C2 == eCont)
2308 					{
2309 						mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SYMMTR;
2310 					}
2311 				}
2312 
2313 				// prepare next polygon step
2314 				aBezier.setStartPoint(aBezier.getEndPoint());
2315 			}
2316 
2317 			if(bClosed)
2318 			{
2319 				// add first point again as closing point due to old definition
2320 				mpImplPolygon->mpPointAry[nArrayInsert] = mpImplPolygon->mpPointAry[0];
2321 				mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
2322 				nArrayInsert++;
2323 			}
2324 			else
2325 			{
2326 				// add last point as closing point
2327 				const basegfx::B2DPoint aClosingPoint(rPolygon.getB2DPoint(nB2DLocalCount - 1L));
2328 				const Point aEnd(FRound(aClosingPoint.getX()), FRound(aClosingPoint.getY()));
2329 				mpImplPolygon->mpPointAry[nArrayInsert] = aEnd;
2330 				mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
2331 				nArrayInsert++;
2332 			}
2333 
2334 			DBG_ASSERT(nArrayInsert <= nMaxTargetCount, "Polygon::Polygon from basegfx::B2DPolygon: wrong max point count estimation (!)");
2335 
2336 			if(nArrayInsert != nMaxTargetCount)
2337 			{
2338 				mpImplPolygon->ImplSetSize(static_cast< sal_uInt16 >(nArrayInsert), true);
2339 			}
2340 		}
2341 	}
2342 	else
2343 	{
2344 		// #127979# Reduce source point count hard to the limit of the tools Polygon
2345 		if(nB2DLocalCount > (0x0000ffff - 1L))
2346 		{
2347 			DBG_ERROR("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
2348 			nB2DLocalCount = (0x0000ffff - 1L);
2349 		}
2350 
2351 		if(nB2DLocalCount)
2352 		{
2353 			// point list creation
2354 			const sal_uInt32 nTargetCount(nB2DLocalCount + (bClosed ? 1L : 0L));
2355 			mpImplPolygon = new ImplPolygon( static_cast< sal_uInt16 >(nTargetCount) );
2356 			sal_uInt16 nIndex(0);
2357 
2358 			for(sal_uInt32 a(0L); a < nB2DLocalCount; a++)
2359 			{
2360 				basegfx::B2DPoint aB2DPoint(rPolygon.getB2DPoint(a));
2361 				Point aPoint(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY()));
2362 				mpImplPolygon->mpPointAry[nIndex++] = aPoint;
2363 			}
2364 
2365 			if(bClosed)
2366 			{
2367 				// add first point as closing point
2368 				mpImplPolygon->mpPointAry[nIndex] = mpImplPolygon->mpPointAry[0];
2369 			}
2370 		}
2371 	}
2372 
2373 	if(!mpImplPolygon)
2374 	{
2375 		// no content yet, create empty polygon
2376 		mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
2377 	}
2378 }
2379 
2380 // eof
2381