xref: /trunk/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