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