xref: /AOO41X/main/tools/source/generic/poly.cxx (revision 8809db7a87f97847b57a57f4cd2b0104b2b83182)
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