xref: /AOO41X/main/tools/source/generic/poly.cxx (revision a61ca253904ee2f33b1db84d2f7bcf9c76adafa6)
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 
ImplPolygon(sal_uInt16 nInitSize,sal_Bool bFlags)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 
ImplPolygon(const ImplPolygon & rImpPoly)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 
ImplPolygon(sal_uInt16 nInitSize,const Point * pInitAry,const sal_uInt8 * pInitFlags)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 
~ImplPolygon()157 ImplPolygon::~ImplPolygon()
158 {
159     if ( mpPointAry )
160     {
161         delete[] (char*) mpPointAry;
162     }
163 
164     if( mpFlagAry )
165         delete[] mpFlagAry;
166 }
167 
168 // -----------------------------------------------------------------------
169 
ImplSetSize(sal_uInt16 nNewSize,sal_Bool bResize)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 
ImplSplit(sal_uInt16 nPos,sal_uInt16 nSpace,ImplPolygon * pInitPoly)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 
ImplRemove(sal_uInt16 nPos,sal_uInt16 nCount)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 
ImplCreateFlagArray()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 
ImplMakeUnique()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 
ImplGetAngle(const Point & rCenter,const Point & rPt)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 
Polygon()372 Polygon::Polygon()
373 {
374     DBG_CTOR( Polygon, NULL );
375     mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
376 }
377 
378 // -----------------------------------------------------------------------
379 
Polygon(sal_uInt16 nSize)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 
Polygon(sal_uInt16 nPoints,const Point * pPtAry,const sal_uInt8 * pFlagAry)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 
Polygon(const Polygon & rPoly)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 
Polygon(const Rectangle & rRect)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 
Polygon(const Rectangle & rRect,sal_uIntPtr nHorzRound,sal_uIntPtr nVertRound)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 
Polygon(const Point & rCenter,long nRadX,long nRadY,sal_uInt16 nPoints)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 
Polygon(const Rectangle & rBound,const Point & rStart,const Point & rEnd,PolyStyle eStyle)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 
Polygon(const Point & rBezPt1,const Point & rCtrlPt1,const Point & rBezPt2,const Point & rCtrlPt2,sal_uInt16 nPoints)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 
~Polygon()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 
ImplGetPointAry()678 Point* Polygon::ImplGetPointAry()
679 {
680     DBG_CHKTHIS( Polygon, NULL );
681 
682     ImplMakeUnique();
683     return (Point*)mpImplPolygon->mpPointAry;
684 }
685 
686 // -----------------------------------------------------------------------
687 
ImplGetFlagAry()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 
GetConstPointAry() const699 const Point* Polygon::GetConstPointAry() const
700 {
701     DBG_CHKTHIS( Polygon, NULL );
702     return (Point*)mpImplPolygon->mpPointAry;
703 }
704 
705 // -----------------------------------------------------------------------
706 
GetConstFlagAry() const707 const sal_uInt8* Polygon::GetConstFlagAry() const
708 {
709     DBG_CHKTHIS( Polygon, NULL );
710     return mpImplPolygon->mpFlagAry;
711 }
712 
713 // -----------------------------------------------------------------------
714 
SetPoint(const Point & rPt,sal_uInt16 nPos)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 
SetFlags(sal_uInt16 nPos,PolyFlags eFlags)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 
GetPoint(sal_uInt16 nPos) const745 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 
GetFlags(sal_uInt16 nPos) const756 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 
HasFlags() const768 sal_Bool Polygon::HasFlags() const
769 {
770     return mpImplPolygon->mpFlagAry != NULL;
771 }
772 
773 // -----------------------------------------------------------------------
774 
IsControl(sal_uInt16 nPos) const775 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 
IsSmooth(sal_uInt16 nPos) const788 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 
IsRect() const801 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 
SetSize(sal_uInt16 nNewSize)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 
GetSize() const834 sal_uInt16 Polygon::GetSize() const
835 {
836     DBG_CHKTHIS( Polygon, NULL );
837 
838     return mpImplPolygon->mnPoints;
839 }
840 
841 // -----------------------------------------------------------------------
842 
Clear()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 
CalcDistance(sal_uInt16 nP1,sal_uInt16 nP2)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 
Optimize(sal_uIntPtr nOptimizeFlags,const PolyOptimizeData * pData)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 */
ImplAdaptiveSubdivide(::std::back_insert_iterator<::std::vector<Point>> & rPointIter,const double old_d2,int recursionDepth,const double d2,const double P1x,const double P1y,const double P2x,const double P2y,const double P3x,const double P3y,const double P4x,const double P4y)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 
AdaptiveSubdivide(Polygon & rResult,const double d) const1042 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             if (aPoints.size() >= SAL_MAX_UINT16)
1081             {
1082                 OSL_ENSURE(aPoints.size() < SAL_MAX_UINT16,
1083                     "Polygon::AdapativeSubdivision created polygon too many points;"
1084                     " using original polygon instead");
1085 
1086                 // The resulting polygon can not hold all the points
1087                 // that we have created so far.  Stop the subdivision
1088                 // and return a copy of the unmodified polygon.
1089                 rResult = *this;
1090                 return;
1091             }
1092         }
1093 
1094         // fill result polygon
1095         rResult = Polygon( (sal_uInt16)aPoints.size() ); // ensure sufficient size for copy
1096         ::std::copy(aPoints.begin(), aPoints.end(), rResult.mpImplPolygon->mpPointAry);
1097     }
1098 }
1099 
1100 // -----------------------------------------------------------------------
1101 
GetIntersection(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1102 void Polygon::GetIntersection( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1103 {
1104     const PolyPolygon aTmp( *this );
1105     aTmp.GetIntersection( rPolyPoly, rResult );
1106 }
1107 
1108 // -----------------------------------------------------------------------
1109 
GetUnion(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1110 void Polygon::GetUnion( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1111 {
1112     const PolyPolygon aTmp( *this );
1113     aTmp.GetUnion( rPolyPoly, rResult );
1114 }
1115 
1116 // -----------------------------------------------------------------------
1117 
GetDifference(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1118 void Polygon::GetDifference( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1119 {
1120     const PolyPolygon aTmp( *this );
1121     aTmp.GetDifference( rPolyPoly, rResult );
1122 }
1123 
1124 // -----------------------------------------------------------------------
1125 
GetXOR(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1126 void Polygon::GetXOR( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1127 {
1128     const PolyPolygon aTmp( *this );
1129     aTmp.GetXOR( rPolyPoly, rResult );
1130 }
1131 
1132 // -----------------------------------------------------------------------
1133 
ImplReduceEdges(Polygon & rPoly,const double & rArea,sal_uInt16 nPercent)1134 void Polygon::ImplReduceEdges( Polygon& rPoly, const double& rArea, sal_uInt16 nPercent )
1135 {
1136     const double    fBound = 2000.0 * ( 100 - nPercent ) * 0.01;
1137     sal_uInt16          nNumNoChange = 0, nNumRuns = 0;
1138 
1139     while( nNumNoChange < 2 )
1140     {
1141         sal_uInt16  nPntCnt = rPoly.GetSize(), nNewPos = 0;
1142         Polygon aNewPoly( nPntCnt );
1143         sal_Bool    bChangeInThisRun = sal_False;
1144 
1145         for( sal_uInt16 n = 0; n < nPntCnt; n++ )
1146         {
1147             sal_Bool bDeletePoint = sal_False;
1148 
1149             if( ( n + nNumRuns ) % 2 )
1150             {
1151                 sal_uInt16      nIndPrev = !n ? nPntCnt - 1 : n - 1;
1152                 sal_uInt16      nIndPrevPrev = !nIndPrev ? nPntCnt - 1 : nIndPrev - 1;
1153                 sal_uInt16      nIndNext = ( n == nPntCnt-1 ) ? 0 : n + 1;
1154                 sal_uInt16      nIndNextNext = ( nIndNext == nPntCnt - 1 ) ? 0 : nIndNext + 1;
1155                 Vector2D    aVec1( rPoly[ nIndPrev ] ); aVec1 -= rPoly[ nIndPrevPrev ];
1156                 Vector2D    aVec2( rPoly[ n ] ); aVec2 -= rPoly[ nIndPrev ];
1157                 Vector2D    aVec3( rPoly[ nIndNext ] ); aVec3 -= rPoly[ n ];
1158                 Vector2D    aVec4( rPoly[ nIndNextNext ] ); aVec4 -= rPoly[ nIndNext ];
1159                 double      fDist1 = aVec1.GetLength(), fDist2 = aVec2.GetLength();
1160                 double      fDist3 = aVec3.GetLength(), fDist4 = aVec4.GetLength();
1161                 double      fTurnB = aVec2.Normalize().Scalar( aVec3.Normalize() );
1162 
1163                 if( fabs( fTurnB ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnB ) > ( 1.0 - SMALL_DVALUE ) )
1164                     bDeletePoint = sal_True;
1165                 else
1166                 {
1167                     Vector2D    aVecB( rPoly[ nIndNext ] );
1168                     double      fDistB = ( aVecB -= rPoly[ nIndPrev ] ).GetLength();
1169                     double      fLenWithB = fDist2 + fDist3;
1170                     double      fLenFact = ( fDistB != 0.0 ) ? fLenWithB / fDistB : 1.0;
1171                     double      fTurnPrev = aVec1.Normalize().Scalar( aVec2 );
1172                     double      fTurnNext = aVec3.Scalar( aVec4.Normalize() );
1173                     double      fGradPrev, fGradB, fGradNext;
1174 
1175                     if( fabs( fTurnPrev ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnPrev ) > ( 1.0 - SMALL_DVALUE ) )
1176                         fGradPrev = 0.0;
1177                     else
1178                         fGradPrev = acos( fTurnPrev ) / ( aVec1.IsNegative( aVec2 ) ? -F_PI180 : F_PI180 );
1179 
1180                     fGradB = acos( fTurnB ) / ( aVec2.IsNegative( aVec3 ) ? -F_PI180 : F_PI180 );
1181 
1182                     if( fabs( fTurnNext ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnNext ) > ( 1.0 - SMALL_DVALUE ) )
1183                         fGradNext = 0.0;
1184                     else
1185                         fGradNext = acos( fTurnNext ) / ( aVec3.IsNegative( aVec4 ) ? -F_PI180 : F_PI180 );
1186 
1187                     if( ( fGradPrev > 0.0 && fGradB < 0.0 && fGradNext > 0.0 ) ||
1188                         ( fGradPrev < 0.0 && fGradB > 0.0 && fGradNext < 0.0 ) )
1189                     {
1190                         if( ( fLenFact < ( FSQRT2 + SMALL_DVALUE ) ) &&
1191                             ( ( ( fDist1 + fDist4 ) / ( fDist2 + fDist3 ) ) * 2000.0 ) > fBound )
1192                         {
1193                             bDeletePoint = sal_True;
1194                         }
1195                     }
1196                     else
1197                     {
1198                         double fRelLen = 1.0 - sqrt( fDistB / rArea );
1199 
1200                         if( fRelLen < 0.0 )
1201                             fRelLen = 0.0;
1202                         else if( fRelLen > 1.0 )
1203                             fRelLen = 1.0;
1204 
1205                         if( ( (sal_uInt32) ( ( ( fLenFact - 1.0 ) * 1000000.0 ) + 0.5 ) < fBound ) &&
1206                             ( fabs( fGradB ) <= ( fRelLen * fBound * 0.01 ) ) )
1207                         {
1208                             bDeletePoint = sal_True;
1209                         }
1210                     }
1211                 }
1212             }
1213 
1214             if( !bDeletePoint )
1215                 aNewPoly[ nNewPos++ ] = rPoly[ n ];
1216             else
1217                 bChangeInThisRun = sal_True;
1218         }
1219 
1220         if( bChangeInThisRun && nNewPos )
1221         {
1222             aNewPoly.SetSize( nNewPos );
1223             rPoly = aNewPoly;
1224             nNumNoChange = 0;
1225         }
1226         else
1227             nNumNoChange++;
1228 
1229         nNumRuns++;
1230     }
1231 }
1232 
1233 // -----------------------------------------------------------------------
1234 
Move(long nHorzMove,long nVertMove)1235 void Polygon::Move( long nHorzMove, long nVertMove )
1236 {
1237     DBG_CHKTHIS( Polygon, NULL );
1238 
1239     // Diese Abfrage sollte man fuer die DrawEngine durchfuehren
1240     if ( !nHorzMove && !nVertMove )
1241         return;
1242 
1243     ImplMakeUnique();
1244 
1245     // Punkte verschieben
1246     sal_uInt16 nCount = mpImplPolygon->mnPoints;
1247     for ( sal_uInt16 i = 0; i < nCount; i++ )
1248     {
1249         Point* pPt = &(mpImplPolygon->mpPointAry[i]);
1250         pPt->X() += nHorzMove;
1251         pPt->Y() += nVertMove;
1252     }
1253 }
1254 
1255 // -----------------------------------------------------------------------
1256 
Translate(const Point & rTrans)1257 void Polygon::Translate(const Point& rTrans)
1258 {
1259     DBG_CHKTHIS( Polygon, NULL );
1260     ImplMakeUnique();
1261 
1262     for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1263         mpImplPolygon->mpPointAry[ i ] += rTrans;
1264 }
1265 
1266 // -----------------------------------------------------------------------
1267 
Scale(double fScaleX,double fScaleY)1268 void Polygon::Scale( double fScaleX, double fScaleY )
1269 {
1270     DBG_CHKTHIS( Polygon, NULL );
1271     ImplMakeUnique();
1272 
1273     for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1274     {
1275         Point& rPnt = mpImplPolygon->mpPointAry[i];
1276         rPnt.X() = (long) ( fScaleX * rPnt.X() );
1277         rPnt.Y() = (long) ( fScaleY * rPnt.Y() );
1278     }
1279 }
1280 
1281 // -----------------------------------------------------------------------
1282 
Rotate(const Point & rCenter,sal_uInt16 nAngle10)1283 void Polygon::Rotate( const Point& rCenter, sal_uInt16 nAngle10 )
1284 {
1285     DBG_CHKTHIS( Polygon, NULL );
1286     nAngle10 %= 3600;
1287 
1288     if( nAngle10 )
1289     {
1290         const double fAngle = F_PI1800 * nAngle10;
1291         Rotate( rCenter, sin( fAngle ), cos( fAngle ) );
1292     }
1293 }
1294 
1295 // -----------------------------------------------------------------------
1296 
Rotate(const Point & rCenter,double fSin,double fCos)1297 void Polygon::Rotate( const Point& rCenter, double fSin, double fCos )
1298 {
1299     DBG_CHKTHIS( Polygon, NULL );
1300     ImplMakeUnique();
1301 
1302     long nX, nY;
1303     long nCenterX = rCenter.X();
1304     long nCenterY = rCenter.Y();
1305 
1306     for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1307     {
1308         Point& rPt = mpImplPolygon->mpPointAry[ i ];
1309 
1310         nX = rPt.X() - nCenterX;
1311         nY = rPt.Y() - nCenterY;
1312         rPt.X() = (long) FRound( fCos * nX + fSin * nY ) + nCenterX;
1313         rPt.Y() = -(long) FRound( fSin * nX - fCos * nY ) + nCenterY;
1314     }
1315 }
1316 
1317 // -----------------------------------------------------------------------
1318 
SlantX(long nYRef,double fSin,double fCos)1319 void Polygon::SlantX( long nYRef, double fSin, double fCos )
1320 {
1321     DBG_CHKTHIS( Polygon, NULL );
1322     ImplMakeUnique();
1323 
1324     for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1325     {
1326         Point&      rPnt = mpImplPolygon->mpPointAry[ i ];
1327         const long  nDy = rPnt.Y() - nYRef;
1328 
1329         rPnt.X() += (long)( fSin * nDy );
1330         rPnt.Y() = nYRef + (long)( fCos * nDy );
1331     }
1332 }
1333 
1334 // -----------------------------------------------------------------------
1335 
SlantY(long nXRef,double fSin,double fCos)1336 void Polygon::SlantY( long nXRef, double fSin, double fCos )
1337 {
1338     DBG_CHKTHIS( Polygon, NULL );
1339     ImplMakeUnique();
1340 
1341     for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1342     {
1343         Point&      rPnt = mpImplPolygon->mpPointAry[ i ];
1344         const long  nDx = rPnt.X() - nXRef;
1345 
1346         rPnt.X() = nXRef + (long)( fCos * nDx );
1347         rPnt.Y() -= (long)( fSin * nDx );
1348     }
1349 }
1350 
1351 // -----------------------------------------------------------------------
1352 
Distort(const Rectangle & rRefRect,const Polygon & rDistortedRect)1353 void Polygon::Distort( const Rectangle& rRefRect, const Polygon& rDistortedRect )
1354 {
1355     DBG_CHKTHIS( Polygon, NULL );
1356     ImplMakeUnique();
1357 
1358     long    Xr, Wr, X1, X2, X3, X4;
1359     long    Yr, Hr, Y1, Y2, Y3, Y4;
1360     double  fTx, fTy, fUx, fUy;
1361 
1362     Xr = rRefRect.Left();
1363     Yr = rRefRect.Top();
1364     Wr = rRefRect.GetWidth();
1365     Hr = rRefRect.GetHeight();
1366 
1367     if( Wr && Hr )
1368     {
1369         DBG_ASSERT( rDistortedRect.mpImplPolygon->mnPoints >= 4, "Distort rect too small!" );
1370 
1371         X1 = rDistortedRect[0].X();
1372         Y1 = rDistortedRect[0].Y();
1373         X2 = rDistortedRect[1].X();
1374         Y2 = rDistortedRect[1].Y();
1375         X3 = rDistortedRect[3].X();
1376         Y3 = rDistortedRect[3].Y();
1377         X4 = rDistortedRect[2].X();
1378         Y4 = rDistortedRect[2].Y();
1379 
1380         for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1381         {
1382             Point& rPnt = mpImplPolygon->mpPointAry[ i ];
1383 
1384             fTx = (double)( rPnt.X() - Xr) / Wr;
1385             fTy = (double)( rPnt.Y() - Yr) / Hr;
1386             fUx = 1.0 - fTx;
1387             fUy = 1.0 - fTy;
1388 
1389             rPnt.X() = (long) ( fUy * (fUx * X1 + fTx * X2) + fTy * (fUx * X3 + fTx * X4) );
1390             rPnt.Y() = (long) ( fUx * (fUy * Y1 + fTy * Y3) + fTx * (fUy * Y2 + fTy * Y4) );
1391         }
1392     }
1393 }
1394 
1395 // -----------------------------------------------------------------------
1396 
1397 class ImplPointFilter
1398 {
1399 public:
1400     virtual void LastPoint() = 0;
1401     virtual void Input( const Point& rPoint ) = 0;
1402 };
1403 
1404 class ImplPolygonPointFilter : public ImplPointFilter
1405 {
1406 public:
1407     ImplPolygon*    mpPoly;     // Nicht loeschen, wird dem Polygon zugewiesen
1408     sal_uInt16          mnSize;
1409 
ImplPolygonPointFilter(sal_uInt16 nDestSize)1410                     ImplPolygonPointFilter( sal_uInt16 nDestSize ) :
1411                         mnSize( 0 )
1412                     {
1413                         mpPoly = new ImplPolygon( nDestSize );
1414                     }
1415 
1416     virtual void    LastPoint();
1417     virtual void    Input( const Point& rPoint );
1418 };
1419 
Input(const Point & rPoint)1420 void ImplPolygonPointFilter::Input( const Point& rPoint )
1421 {
1422     if ( !mnSize || (rPoint != mpPoly->mpPointAry[mnSize-1]) )
1423     {
1424         mnSize++;
1425         if ( mnSize > mpPoly->mnPoints )
1426             mpPoly->ImplSetSize( mnSize );
1427         mpPoly->mpPointAry[mnSize-1] = rPoint;
1428     }
1429 }
1430 
LastPoint()1431 void ImplPolygonPointFilter::LastPoint()
1432 {
1433     if ( mnSize < mpPoly->mnPoints )
1434         mpPoly->ImplSetSize( mnSize );
1435 };
1436 
1437 class ImplEdgePointFilter : public ImplPointFilter
1438 {
1439     Point               maFirstPoint;
1440     Point               maLastPoint;
1441     ImplPointFilter&    mrNextFilter;
1442     const long          mnLow;
1443     const long          mnHigh;
1444     const int           mnEdge;
1445     int                 mnLastOutside;
1446     sal_Bool                mbFirst;
1447 
1448 public:
ImplEdgePointFilter(int nEdge,long nLow,long nHigh,ImplPointFilter & rNextFilter)1449                         ImplEdgePointFilter( int nEdge, long nLow, long nHigh,
1450                                              ImplPointFilter& rNextFilter ) :
1451                             mrNextFilter( rNextFilter ),
1452                             mnLow( nLow ),
1453                             mnHigh( nHigh ),
1454                             mnEdge( nEdge ),
1455                             mbFirst( sal_True )
1456                         {
1457                         }
1458 
1459     Point               EdgeSection( const Point& rPoint, int nEdge ) const;
1460     int                 VisibleSide( const Point& rPoint ) const;
IsPolygon() const1461     int                 IsPolygon() const
1462                             { return maFirstPoint == maLastPoint; }
1463 
1464     virtual void        Input( const Point& rPoint );
1465     virtual void        LastPoint();
1466 };
1467 
VisibleSide(const Point & rPoint) const1468 inline int ImplEdgePointFilter::VisibleSide( const Point& rPoint ) const
1469 {
1470     if ( mnEdge & EDGE_HORZ )
1471     {
1472         return rPoint.X() < mnLow ? EDGE_LEFT :
1473                                      rPoint.X() > mnHigh ? EDGE_RIGHT : 0;
1474     }
1475     else
1476     {
1477         return rPoint.Y() < mnLow ? EDGE_TOP :
1478                                      rPoint.Y() > mnHigh ? EDGE_BOTTOM : 0;
1479     }
1480 }
1481 
EdgeSection(const Point & rPoint,int nEdge) const1482 Point ImplEdgePointFilter::EdgeSection( const Point& rPoint, int nEdge ) const
1483 {
1484     long lx = maLastPoint.X();
1485     long ly = maLastPoint.Y();
1486     long md = rPoint.X() - lx;
1487     long mn = rPoint.Y() - ly;
1488     long nNewX;
1489     long nNewY;
1490 
1491     if ( nEdge & EDGE_VERT )
1492     {
1493         nNewY = (nEdge == EDGE_TOP) ? mnLow : mnHigh;
1494         long dy = nNewY - ly;
1495         if ( !md )
1496             nNewX = lx;
1497         else if ( (LONG_MAX / Abs(md)) >= Abs(dy) )
1498             nNewX = (dy * md) / mn + lx;
1499         else
1500         {
1501             BigInt ady = dy;
1502             ady *= md;
1503             if( ady.IsNeg() )
1504                 if( mn < 0 )
1505                     ady += mn/2;
1506                 else
1507                     ady -= (mn-1)/2;
1508             else
1509                 if( mn < 0 )
1510                     ady -= (mn+1)/2;
1511                 else
1512                     ady += mn/2;
1513             ady /= mn;
1514             nNewX = (long)ady + lx;
1515         }
1516     }
1517     else
1518     {
1519         nNewX = (nEdge == EDGE_LEFT) ? mnLow : mnHigh;
1520         long dx = nNewX - lx;
1521         if ( !mn )
1522             nNewY = ly;
1523         else if ( (LONG_MAX / Abs(mn)) >= Abs(dx) )
1524             nNewY = (dx * mn) / md + ly;
1525         else
1526         {
1527             BigInt adx = dx;
1528             adx *= mn;
1529             if( adx.IsNeg() )
1530                 if( md < 0 )
1531                     adx += md/2;
1532                 else
1533                     adx -= (md-1)/2;
1534             else
1535                 if( md < 0 )
1536                     adx -= (md+1)/2;
1537                 else
1538                     adx += md/2;
1539             adx /= md;
1540             nNewY = (long)adx + ly;
1541         }
1542     }
1543 
1544     return Point( nNewX, nNewY );
1545 }
1546 
Input(const Point & rPoint)1547 void ImplEdgePointFilter::Input( const Point& rPoint )
1548 {
1549     int nOutside = VisibleSide( rPoint );
1550 
1551     if ( mbFirst )
1552     {
1553         maFirstPoint = rPoint;
1554         mbFirst      = sal_False;
1555         if ( !nOutside )
1556             mrNextFilter.Input( rPoint );
1557     }
1558     else if ( rPoint == maLastPoint )
1559         return;
1560     else if ( !nOutside )
1561     {
1562         if ( mnLastOutside )
1563             mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1564         mrNextFilter.Input( rPoint );
1565     }
1566     else if ( !mnLastOutside )
1567         mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1568     else if ( nOutside != mnLastOutside )
1569     {
1570         mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1571         mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1572     }
1573 
1574     maLastPoint    = rPoint;
1575     mnLastOutside  = nOutside;
1576 }
1577 
LastPoint()1578 void ImplEdgePointFilter::LastPoint()
1579 {
1580     if ( !mbFirst )
1581     {
1582         int nOutside = VisibleSide( maFirstPoint );
1583 
1584         if ( nOutside != mnLastOutside )
1585             Input( maFirstPoint );
1586         mrNextFilter.LastPoint();
1587     }
1588 }
1589 
1590 // -----------------------------------------------------------------------
1591 
Clip(const Rectangle & rRect,sal_Bool bPolygon)1592 void Polygon::Clip( const Rectangle& rRect, sal_Bool bPolygon )
1593 {
1594     // #105251# Justify rect befor edge filtering
1595     Rectangle               aJustifiedRect( rRect );
1596     aJustifiedRect.Justify();
1597 
1598     sal_uInt16                  nSourceSize = mpImplPolygon->mnPoints;
1599     ImplPolygonPointFilter  aPolygon( nSourceSize );
1600     ImplEdgePointFilter     aHorzFilter( EDGE_HORZ, aJustifiedRect.Left(), aJustifiedRect.Right(),
1601                                          aPolygon );
1602     ImplEdgePointFilter     aVertFilter( EDGE_VERT, aJustifiedRect.Top(), aJustifiedRect.Bottom(),
1603                                          aHorzFilter );
1604 
1605     for ( sal_uInt16 i = 0; i < nSourceSize; i++ )
1606         aVertFilter.Input( mpImplPolygon->mpPointAry[i] );
1607     if ( bPolygon || aVertFilter.IsPolygon() )
1608         aVertFilter.LastPoint();
1609     else
1610         aPolygon.LastPoint();
1611 
1612     // Alte ImpPolygon-Daten loeschen und die vom ImpPolygonPointFilter
1613     // zuweisen
1614     if ( mpImplPolygon->mnRefCount )
1615     {
1616         if ( mpImplPolygon->mnRefCount > 1 )
1617             mpImplPolygon->mnRefCount--;
1618         else
1619             delete mpImplPolygon;
1620     }
1621     mpImplPolygon = aPolygon.mpPoly;
1622 }
1623 
1624 // -----------------------------------------------------------------------
1625 
GetBoundRect() const1626 Rectangle Polygon::GetBoundRect() const
1627 {
1628     DBG_CHKTHIS( Polygon, NULL );
1629     // Removing the assert. Bezier curves have the attribute that each single
1630     // curve segment defined by four points can not exit the four-point polygon
1631     // defined by that points. This allows to say that the curve segment can also
1632     // never leave the Range of it's defining points.
1633     // The result is that Polygon::GetBoundRect() may not create the minimal
1634     // BoundRect of the Polygon (to get that, use basegfx::B2DPolygon classes),
1635     // but will always create a valid BoundRect, at least as long as this method
1636     // 'blindly' travels over all points, including control points.
1637     //
1638     // DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetBoundRect could fail with beziers!" );
1639 
1640     sal_uInt16  nCount = mpImplPolygon->mnPoints;
1641     if( ! nCount )
1642         return Rectangle();
1643 
1644     long    nXMin, nXMax, nYMin, nYMax;
1645 
1646     const Point* pPt = &(mpImplPolygon->mpPointAry[0]);
1647     nXMin = nXMax = pPt->X();
1648     nYMin = nYMax = pPt->Y();
1649 
1650     for ( sal_uInt16 i = 0; i < nCount; i++ )
1651     {
1652         pPt = &(mpImplPolygon->mpPointAry[i]);
1653 
1654         if ( pPt->X() < nXMin )
1655             nXMin = pPt->X();
1656         if ( pPt->X() > nXMax )
1657             nXMax = pPt->X();
1658         if ( pPt->Y() < nYMin )
1659             nYMin = pPt->Y();
1660         if ( pPt->Y() > nYMax )
1661             nYMax = pPt->Y();
1662     }
1663 
1664     return Rectangle( nXMin, nYMin, nXMax, nYMax );
1665 }
1666 
1667 // -----------------------------------------------------------------------
1668 
GetArea() const1669 double Polygon::GetArea() const
1670 {
1671     const double fArea = GetSignedArea();
1672     return( ( fArea < 0.0 ) ? -fArea : fArea );
1673 }
1674 
1675 // -----------------------------------------------------------------------
1676 
GetSignedArea() const1677 double Polygon::GetSignedArea() const
1678 {
1679     DBG_CHKTHIS( Polygon, NULL );
1680     DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetArea could fail with beziers!" );
1681 
1682     double fArea = 0.0;
1683 
1684     if( mpImplPolygon->mnPoints > 2 )
1685     {
1686         const sal_uInt16 nCount1 = mpImplPolygon->mnPoints - 1;
1687 
1688         for( sal_uInt16 i = 0; i < nCount1; )
1689         {
1690             const Point& rPt = mpImplPolygon->mpPointAry[ i ];
1691             const Point& rPt1 = mpImplPolygon->mpPointAry[ ++i ];
1692             fArea += ( rPt.X() - rPt1.X() ) * ( rPt.Y() + rPt1.Y() );
1693         }
1694 
1695         const Point& rPt = mpImplPolygon->mpPointAry[ nCount1 ];
1696         const Point& rPt0 = mpImplPolygon->mpPointAry[ 0 ];
1697         fArea += ( rPt.X() - rPt0.X() ) * ( rPt.Y() + rPt0.Y() );
1698     }
1699 
1700     return fArea;
1701 }
1702 
1703 // -----------------------------------------------------------------------
1704 
IsInside(const Point & rPoint) const1705 sal_Bool Polygon::IsInside( const Point& rPoint ) const
1706 {
1707     DBG_CHKTHIS( Polygon, NULL );
1708     DBG_ASSERT( !mpImplPolygon->mpFlagAry, "IsInside could fail with beziers!" );
1709 
1710     const Rectangle aBound( GetBoundRect() );
1711     const Line      aLine( rPoint, Point( aBound.Right() + 100L, rPoint.Y() ) );
1712     sal_uInt16          nCount = mpImplPolygon->mnPoints;
1713     sal_uInt16          nPCounter = 0;
1714 
1715     if ( ( nCount > 2 ) && aBound.IsInside( rPoint ) )
1716     {
1717         Point   aPt1( mpImplPolygon->mpPointAry[ 0 ] );
1718         Point   aIntersection;
1719         Point   aLastIntersection;
1720 
1721         while ( ( aPt1 == mpImplPolygon->mpPointAry[ nCount - 1 ] ) && ( nCount > 3 ) )
1722             nCount--;
1723 
1724         for ( sal_uInt16 i = 1; i <= nCount; i++ )
1725         {
1726             const Point& rPt2 = mpImplPolygon->mpPointAry[ ( i < nCount ) ? i : 0 ];
1727 
1728             if ( aLine.Intersection( Line( aPt1, rPt2 ), aIntersection ) )
1729             {
1730                 // Hiermit verhindern wir das Einfuegen von
1731                 // doppelten Intersections, die gleich hintereinander folgen
1732                 if ( nPCounter )
1733                 {
1734                     if ( aIntersection != aLastIntersection )
1735                     {
1736                         aLastIntersection = aIntersection;
1737                         nPCounter++;
1738                     }
1739                 }
1740                 else
1741                 {
1742                     aLastIntersection = aIntersection;
1743                     nPCounter++;
1744                 }
1745             }
1746 
1747             aPt1 = rPt2;
1748         }
1749     }
1750 
1751     // innerhalb, wenn die Anzahl der Schnittpunkte ungerade ist
1752     return ( ( nPCounter & 1 ) == 1 );
1753 }
1754 
1755 // -----------------------------------------------------------------------
1756 
IsRightOrientated() const1757 sal_Bool Polygon::IsRightOrientated() const
1758 {
1759     DBG_CHKTHIS( Polygon, NULL );
1760     return GetSignedArea() >= 0.0;
1761 }
1762 
1763 // -----------------------------------------------------------------------
1764 
Insert(sal_uInt16 nPos,const Point & rPt,PolyFlags eFlags)1765 void Polygon::Insert( sal_uInt16 nPos, const Point& rPt, PolyFlags eFlags )
1766 {
1767     DBG_CHKTHIS( Polygon, NULL );
1768     ImplMakeUnique();
1769 
1770     if( nPos >= mpImplPolygon->mnPoints )
1771         nPos = mpImplPolygon->mnPoints;
1772 
1773     mpImplPolygon->ImplSplit( nPos, 1 );
1774     mpImplPolygon->mpPointAry[ nPos ] = rPt;
1775 
1776     if( POLY_NORMAL != eFlags )
1777     {
1778         mpImplPolygon->ImplCreateFlagArray();
1779         mpImplPolygon->mpFlagAry[ nPos ] = (sal_uInt8) eFlags;
1780     }
1781 }
1782 
1783 // -----------------------------------------------------------------------
1784 
Insert(sal_uInt16 nPos,const Polygon & rPoly)1785 void Polygon::Insert( sal_uInt16 nPos, const Polygon& rPoly )
1786 {
1787     DBG_CHKTHIS( Polygon, NULL );
1788     const sal_uInt16 nInsertCount = rPoly.mpImplPolygon->mnPoints;
1789 
1790     if( nInsertCount )
1791     {
1792         ImplMakeUnique();
1793 
1794         if( nPos >= mpImplPolygon->mnPoints )
1795             nPos = mpImplPolygon->mnPoints;
1796 
1797         if( rPoly.mpImplPolygon->mpFlagAry )
1798             mpImplPolygon->ImplCreateFlagArray();
1799 
1800         mpImplPolygon->ImplSplit( nPos, nInsertCount, rPoly.mpImplPolygon );
1801     }
1802 }
1803 
1804 // -----------------------------------------------------------------------
1805 
Remove(sal_uInt16 nPos,sal_uInt16 nCount)1806 void Polygon::Remove( sal_uInt16 nPos, sal_uInt16 nCount )
1807 {
1808     DBG_CHKTHIS( Polygon, NULL );
1809     if( nCount && ( nPos < mpImplPolygon->mnPoints ) )
1810     {
1811         ImplMakeUnique();
1812         mpImplPolygon->ImplRemove( nPos, nCount );
1813     }
1814 }
1815 
1816 // -----------------------------------------------------------------------
1817 
operator [](sal_uInt16 nPos)1818 Point& Polygon::operator[]( sal_uInt16 nPos )
1819 {
1820     DBG_CHKTHIS( Polygon, NULL );
1821     DBG_ASSERT( nPos < mpImplPolygon->mnPoints, "Polygon::[]: nPos >= nPoints" );
1822 
1823     ImplMakeUnique();
1824     return mpImplPolygon->mpPointAry[nPos];
1825 }
1826 
1827 // -----------------------------------------------------------------------
1828 
operator =(const Polygon & rPoly)1829 Polygon& Polygon::operator=( const Polygon& rPoly )
1830 {
1831     DBG_CHKTHIS( Polygon, NULL );
1832     DBG_CHKOBJ( &rPoly, Polygon, NULL );
1833     DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
1834 
1835     // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
1836     // RefCount == 0 fuer statische Objekte
1837     if ( rPoly.mpImplPolygon->mnRefCount )
1838         rPoly.mpImplPolygon->mnRefCount++;
1839 
1840     // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
1841     // die letzte Referenz ist, sonst Referenzcounter decrementieren
1842     if ( mpImplPolygon->mnRefCount )
1843     {
1844         if ( mpImplPolygon->mnRefCount > 1 )
1845             mpImplPolygon->mnRefCount--;
1846         else
1847             delete mpImplPolygon;
1848     }
1849 
1850     mpImplPolygon = rPoly.mpImplPolygon;
1851     return *this;
1852 }
1853 
1854 // -----------------------------------------------------------------------
1855 
operator ==(const Polygon & rPoly) const1856 sal_Bool Polygon::operator==( const Polygon& rPoly ) const
1857 {
1858     DBG_CHKTHIS( Polygon, NULL );
1859     DBG_CHKOBJ( &rPoly, Polygon, NULL );
1860 
1861     if ( (rPoly.mpImplPolygon == mpImplPolygon) )
1862         return sal_True;
1863     else
1864         return sal_False;
1865 }
1866 
1867 // -----------------------------------------------------------------------
1868 
IsEqual(const Polygon & rPoly) const1869 sal_Bool Polygon::IsEqual( const Polygon& rPoly ) const
1870 {
1871     sal_Bool bIsEqual = sal_True;;
1872     sal_uInt16 i;
1873     if ( GetSize() != rPoly.GetSize() )
1874         bIsEqual = sal_False;
1875     else
1876     {
1877         for ( i = 0; i < GetSize(); i++ )
1878         {
1879             if ( ( GetPoint( i ) != rPoly.GetPoint( i ) ) ||
1880                 ( GetFlags( i ) != rPoly.GetFlags( i ) ) )
1881             {
1882                 bIsEqual = sal_False;
1883                 break;
1884             }
1885         }
1886     }
1887     return bIsEqual;
1888 }
1889 
1890 // -----------------------------------------------------------------------
1891 
operator >>(SvStream & rIStream,Polygon & rPoly)1892 SvStream& operator>>( SvStream& rIStream, Polygon& rPoly )
1893 {
1894     DBG_CHKOBJ( &rPoly, Polygon, NULL );
1895     DBG_ASSERTWARNING( rIStream.GetVersion(), "Polygon::>> - Solar-Version not set on rIStream" );
1896 
1897     sal_uInt16          i;
1898     sal_uInt16          nStart;
1899     sal_uInt16          nCurPoints;
1900     sal_uInt16          nPoints;
1901     unsigned char   bShort;
1902     short           nShortX;
1903     short           nShortY;
1904     long            nLongX;
1905     long            nLongY;
1906 
1907     // Anzahl der Punkte einlesen und Array erzeugen
1908     rIStream >> nPoints;
1909     if ( rPoly.mpImplPolygon->mnRefCount != 1 )
1910     {
1911         if ( rPoly.mpImplPolygon->mnRefCount )
1912             rPoly.mpImplPolygon->mnRefCount--;
1913         rPoly.mpImplPolygon = new ImplPolygon( nPoints );
1914     }
1915     else
1916         rPoly.mpImplPolygon->ImplSetSize( nPoints, sal_False );
1917 
1918     // Je nach CompressMode das Polygon einlesen
1919     if ( rIStream.GetCompressMode() == COMPRESSMODE_FULL )
1920     {
1921         i = 0;
1922         while ( i < nPoints )
1923         {
1924             rIStream >> bShort >> nCurPoints;
1925 
1926             if ( bShort )
1927             {
1928                 for ( nStart = i; i < nStart+nCurPoints; i++ )
1929                 {
1930                     rIStream >> nShortX >> nShortY;
1931                     rPoly.mpImplPolygon->mpPointAry[i].X() = nShortX;
1932                     rPoly.mpImplPolygon->mpPointAry[i].Y() = nShortY;
1933                 }
1934             }
1935             else
1936             {
1937                 for ( nStart = i; i < nStart+nCurPoints; i++ )
1938                 {
1939                     rIStream >> nLongX >> nLongY;
1940                     rPoly.mpImplPolygon->mpPointAry[i].X() = nLongX;
1941                     rPoly.mpImplPolygon->mpPointAry[i].Y() = nLongY;
1942                 }
1943             }
1944         }
1945     }
1946     else
1947     {
1948         // Feststellen, ob ueber die Operatoren geschrieben werden muss
1949 #if (SAL_TYPES_SIZEOFLONG) != 4
1950         if ( 1 )
1951 #else
1952 #ifdef OSL_BIGENDIAN
1953         if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
1954 #else
1955         if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
1956 #endif
1957 #endif
1958         {
1959             for( i = 0; i < nPoints; i++ )
1960             {
1961                 rIStream >> rPoly.mpImplPolygon->mpPointAry[i].X()
1962                          >> rPoly.mpImplPolygon->mpPointAry[i].Y();
1963             }
1964         }
1965         else
1966             rIStream.Read( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
1967     }
1968 
1969     return rIStream;
1970 }
1971 
1972 // -----------------------------------------------------------------------
1973 
operator <<(SvStream & rOStream,const Polygon & rPoly)1974 SvStream& operator<<( SvStream& rOStream, const Polygon& rPoly )
1975 {
1976     DBG_CHKOBJ( &rPoly, Polygon, NULL );
1977     DBG_ASSERTWARNING( rOStream.GetVersion(), "Polygon::<< - Solar-Version not set on rOStream" );
1978 
1979     unsigned char   bShort;
1980     unsigned char   bCurShort;
1981     sal_uInt16          nStart;
1982     sal_uInt16          i;
1983     sal_uInt16          nPoints = rPoly.GetSize();
1984 
1985     // Anzahl der Punkte rausschreiben
1986     rOStream << nPoints;
1987 
1988     // Je nach CompressMode das Polygon rausschreiben
1989     if ( rOStream.GetCompressMode() == COMPRESSMODE_FULL )
1990     {
1991         i = 0;
1992         while ( i < nPoints )
1993         {
1994             nStart = i;
1995 
1996             // Feststellen, welcher Typ geschrieben werden soll
1997             if ( ((rPoly.mpImplPolygon->mpPointAry[nStart].X() >= SHRT_MIN) &&
1998                   (rPoly.mpImplPolygon->mpPointAry[nStart].X() <= SHRT_MAX)) &&
1999                  ((rPoly.mpImplPolygon->mpPointAry[nStart].Y() >= SHRT_MIN) &&
2000                   (rPoly.mpImplPolygon->mpPointAry[nStart].Y() <= SHRT_MAX)) )
2001                 bShort = sal_True;
2002             else
2003                 bShort = sal_False;
2004             while ( i < nPoints )
2005             {
2006                 // Feststellen, welcher Typ geschrieben werden soll
2007                 if ( ((rPoly.mpImplPolygon->mpPointAry[nStart].X() >= SHRT_MIN) &&
2008                       (rPoly.mpImplPolygon->mpPointAry[nStart].X() <= SHRT_MAX)) &&
2009                      ((rPoly.mpImplPolygon->mpPointAry[nStart].Y() >= SHRT_MIN) &&
2010                       (rPoly.mpImplPolygon->mpPointAry[nStart].Y() <= SHRT_MAX)) )
2011                     bCurShort = sal_True;
2012                 else
2013                     bCurShort = sal_False;
2014 
2015                 // Wenn sich die Werte in einen anderen Bereich begeben,
2016                 // muessen wir neu rausschreiben
2017                 if ( bCurShort != bShort )
2018                 {
2019                     bShort = bCurShort;
2020                     break;
2021                 }
2022 
2023                 i++;
2024             }
2025 
2026             rOStream << bShort << (sal_uInt16)(i-nStart);
2027 
2028             if ( bShort )
2029             {
2030                 for( ; nStart < i; nStart++ )
2031                 {
2032                     rOStream << (short)rPoly.mpImplPolygon->mpPointAry[nStart].X()
2033                              << (short)rPoly.mpImplPolygon->mpPointAry[nStart].Y();
2034                 }
2035             }
2036             else
2037             {
2038                 for( ; nStart < i; nStart++ )
2039                 {
2040                     rOStream << rPoly.mpImplPolygon->mpPointAry[nStart].X()
2041                              << rPoly.mpImplPolygon->mpPointAry[nStart].Y();
2042                 }
2043             }
2044         }
2045     }
2046     else
2047     {
2048         // Feststellen, ob ueber die Operatoren geschrieben werden muss
2049 #if (SAL_TYPES_SIZEOFLONG) != 4
2050         if ( 1 )
2051 #else
2052 #ifdef OSL_BIGENDIAN
2053         if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
2054 #else
2055         if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
2056 #endif
2057 #endif
2058         {
2059             for( i = 0; i < nPoints; i++ )
2060             {
2061                 rOStream << rPoly.mpImplPolygon->mpPointAry[i].X()
2062                          << rPoly.mpImplPolygon->mpPointAry[i].Y();
2063             }
2064         }
2065         else
2066         {
2067             if ( nPoints )
2068                 rOStream.Write( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
2069         }
2070     }
2071 
2072     return rOStream;
2073 }
2074 
2075 // -----------------------------------------------------------------------
2076 
ImplRead(SvStream & rIStream)2077 void Polygon::ImplRead( SvStream& rIStream )
2078 {
2079     sal_uInt8   bHasPolyFlags;
2080 
2081     rIStream >> *this
2082              >> bHasPolyFlags;
2083 
2084     if ( bHasPolyFlags )
2085     {
2086         mpImplPolygon->mpFlagAry = new sal_uInt8[ mpImplPolygon->mnPoints ];
2087         rIStream.Read( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
2088     }
2089 }
2090 
2091 // -----------------------------------------------------------------------
2092 
Read(SvStream & rIStream)2093 void Polygon::Read( SvStream& rIStream )
2094 {
2095     VersionCompat aCompat( rIStream, STREAM_READ );
2096 
2097     ImplRead( rIStream );
2098 }
2099 
2100 // -----------------------------------------------------------------------
2101 
ImplWrite(SvStream & rOStream) const2102 void Polygon::ImplWrite( SvStream& rOStream ) const
2103 {
2104     sal_uInt8   bHasPolyFlags = mpImplPolygon->mpFlagAry != NULL;
2105     rOStream << *this
2106              << bHasPolyFlags;
2107 
2108     if ( bHasPolyFlags )
2109         rOStream.Write( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
2110 }
2111 
2112 // -----------------------------------------------------------------------
2113 
Write(SvStream & rOStream) const2114 void Polygon::Write( SvStream& rOStream ) const
2115 {
2116     VersionCompat aCompat( rOStream, STREAM_WRITE, 1 );
2117 
2118     ImplWrite( rOStream );
2119 }
2120 
2121 // -----------------------------------------------------------------------
2122 // numerical correction method for B2DPolygon
impCorrectContinuity(basegfx::B2DPolygon & roPolygon,sal_uInt32 nIndex,sal_uInt8 nCFlag)2123 void impCorrectContinuity(basegfx::B2DPolygon& roPolygon, sal_uInt32 nIndex, sal_uInt8 nCFlag)
2124 {
2125     const sal_uInt32 nPointCount(roPolygon.count());
2126     OSL_ENSURE(nIndex < nPointCount, "impCorrectContinuity: index access out of range (!)");
2127 
2128     if(nIndex < nPointCount && (POLY_SMOOTH == nCFlag || POLY_SYMMTR == nCFlag))
2129     {
2130         if(roPolygon.isPrevControlPointUsed(nIndex) && roPolygon.isNextControlPointUsed(nIndex))
2131         {
2132             // #115917# Patch from osnola (modified, thanks for showing the porblem)
2133             //
2134             // The correction is needed because an integer polygon with control points
2135             // is converted to double precision. When C1 or C2 is used the involved vectors
2136             // may not have the same directions/lengths since these come from integer coordinates
2137             //  and may have been snapped to different nearest integer coordinates. The snap error
2138             // is in the range of +-1 in y and y, thus 0.0 <= error <= sqrt(2.0). Nonetheless,
2139             // it needs to be corrected to be able to detect the continuity in this points
2140             // correctly.
2141             //
2142             // We only have the integer data here (already in double precision form, but no mantisses
2143             // used), so the best correction is to use:
2144             //
2145             // for C1: The longest vector since it potentially has best preserved the original vector.
2146             //         Even better the sum of the vectors, weighted by their length. This gives the
2147             //         normal vector addition to get the vector itself, lengths need to be preserved.
2148             // for C2: The mediated vector(s) since both should be the same, but mirrored
2149 
2150             // extract the point and vectors
2151             const basegfx::B2DPoint aPoint(roPolygon.getB2DPoint(nIndex));
2152             const basegfx::B2DVector aNext(roPolygon.getNextControlPoint(nIndex) - aPoint);
2153             const basegfx::B2DVector aPrev(aPoint - roPolygon.getPrevControlPoint(nIndex));
2154 
2155             // calculate common direction vector, normalize
2156             const basegfx::B2DVector aDirection(aNext + aPrev);
2157 
2158             if(POLY_SMOOTH == nCFlag)
2159             {
2160                 // C1: apply common direction vector, preserve individual lengths
2161                 const double fInvDirectionLen(1.0 / aDirection.getLength());
2162                 roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + (aDirection * (aNext.getLength() * fInvDirectionLen))));
2163                 roPolygon.setPrevControlPoint(nIndex, basegfx::B2DPoint(aPoint - (aDirection * (aPrev.getLength() * fInvDirectionLen))));
2164             }
2165             else // POLY_SYMMTR
2166             {
2167                 // C2: get mediated length. Taking half of the unnormalized direction would be
2168                 // an approximation, but not correct.
2169                 const double fMedLength((aNext.getLength() + aPrev.getLength()) * (0.5 / aDirection.getLength()));
2170                 const basegfx::B2DVector aScaledDirection(aDirection * fMedLength);
2171 
2172                 // Bring Direction to correct length and apply
2173                 roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + aScaledDirection));
2174                 roPolygon.setPrevControlPoint(nIndex, basegfx::B2DPoint(aPoint - aScaledDirection));
2175             }
2176         }
2177     }
2178 }
2179 
2180 // -----------------------------------------------------------------------
2181 // convert to basegfx::B2DPolygon and return
getB2DPolygon() const2182 basegfx::B2DPolygon Polygon::getB2DPolygon() const
2183 {
2184     basegfx::B2DPolygon aRetval;
2185     const sal_uInt16 nCount(mpImplPolygon->mnPoints);
2186 
2187     if(nCount)
2188     {
2189         if(mpImplPolygon->mpFlagAry)
2190         {
2191             // handling for curves. Add start point
2192             const Point aStartPoint(mpImplPolygon->mpPointAry[0]);
2193             sal_uInt8 nPointFlag(mpImplPolygon->mpFlagAry[0]);
2194             aRetval.append(basegfx::B2DPoint(aStartPoint.X(), aStartPoint.Y()));
2195             Point aControlA, aControlB;
2196 
2197             for(sal_uInt16 a(1); a < nCount;)
2198             {
2199                 bool bControlA(false);
2200                 bool bControlB(false);
2201 
2202                 if(POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
2203                 {
2204                     aControlA = mpImplPolygon->mpPointAry[a++];
2205                     bControlA = true;
2206                 }
2207 
2208                 if(a < nCount && POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
2209                 {
2210                     aControlB = mpImplPolygon->mpPointAry[a++];
2211                     bControlB = true;
2212                 }
2213 
2214                 // assert invalid polygons
2215                 OSL_ENSURE(bControlA == bControlB, "Polygon::getB2DPolygon: Invalid source polygon (!)");
2216 
2217                 if(a < nCount)
2218                 {
2219                     const Point aEndPoint(mpImplPolygon->mpPointAry[a]);
2220 
2221                     if(bControlA)
2222                     {
2223                         // bezier edge, add
2224                         aRetval.appendBezierSegment(
2225                             basegfx::B2DPoint(aControlA.X(), aControlA.Y()),
2226                             basegfx::B2DPoint(aControlB.X(), aControlB.Y()),
2227                             basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
2228 
2229                         impCorrectContinuity(aRetval, aRetval.count() - 2, nPointFlag);
2230                     }
2231                     else
2232                     {
2233                         // no bezier edge, add end point
2234                         aRetval.append(basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
2235                     }
2236 
2237                     nPointFlag = mpImplPolygon->mpFlagAry[a++];
2238                 }
2239             }
2240 
2241             // if exist, remove double first/last points, set closed and correct control points
2242             basegfx::tools::checkClosed(aRetval);
2243 
2244             if(aRetval.isClosed())
2245             {
2246                 // closeWithGeometryChange did really close, so last point(s) were removed.
2247                 // Correct the continuity in the changed point
2248                 impCorrectContinuity(aRetval, 0, mpImplPolygon->mpFlagAry[0]);
2249             }
2250         }
2251         else
2252         {
2253             // extra handling for non-curves (most-used case) for speedup
2254             for(sal_uInt16 a(0); a < nCount; a++)
2255             {
2256                 // get point and add
2257                 const Point aPoint(mpImplPolygon->mpPointAry[a]);
2258                 aRetval.append(basegfx::B2DPoint(aPoint.X(), aPoint.Y()));
2259             }
2260 
2261             // set closed flag
2262             basegfx::tools::checkClosed(aRetval);
2263         }
2264     }
2265 
2266     return aRetval;
2267 }
2268 
2269 // -----------------------------------------------------------------------
2270 // constructor to convert from basegfx::B2DPolygon
2271 // #i76891# Needed to change from adding all control points (even for unused
2272 // edges) and creating a fixed-size Polygon in the first run to creating the
2273 // minimal Polygon. This requires a temporary Point- and Flag-Array for curves
2274 // and a memcopy at ImplPolygon creation, but contains no zero-controlpoints
2275 // for straight edges.
Polygon(const basegfx::B2DPolygon & rPolygon)2276 Polygon::Polygon(const basegfx::B2DPolygon& rPolygon)
2277 :   mpImplPolygon(0)
2278 {
2279     DBG_CTOR( Polygon, NULL );
2280 
2281     const bool bCurve(rPolygon.areControlPointsUsed());
2282     const bool bClosed(rPolygon.isClosed());
2283     sal_uInt32 nB2DLocalCount(rPolygon.count());
2284 
2285     if(bCurve)
2286     {
2287         // #127979# Reduce source point count hard to the limit of the tools Polygon
2288         if(nB2DLocalCount > ((0x0000ffff / 3L) - 1L))
2289         {
2290             DBG_ERROR("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
2291             nB2DLocalCount = ((0x0000ffff / 3L) - 1L);
2292         }
2293 
2294         // calculate target point count
2295         const sal_uInt32 nLoopCount(bClosed ? nB2DLocalCount : (nB2DLocalCount ? nB2DLocalCount - 1L : 0L ));
2296 
2297         if(nLoopCount)
2298         {
2299             // calculate maximum array size and allocate; prepare insert index
2300             const sal_uInt32 nMaxTargetCount((nLoopCount * 3) + 1);
2301             mpImplPolygon = new ImplPolygon(static_cast< sal_uInt16 >(nMaxTargetCount), true);
2302 
2303             // prepare insert index and current point
2304             sal_uInt32 nArrayInsert(0);
2305             basegfx::B2DCubicBezier aBezier;
2306             aBezier.setStartPoint(rPolygon.getB2DPoint(0));
2307 
2308             for(sal_uInt32 a(0L); a < nLoopCount; a++)
2309             {
2310                 // add current point (always) and remember StartPointIndex for evtl. later corrections
2311                 const Point aStartPoint(FRound(aBezier.getStartPoint().getX()), FRound(aBezier.getStartPoint().getY()));
2312                 const sal_uInt32 nStartPointIndex(nArrayInsert);
2313                 mpImplPolygon->mpPointAry[nStartPointIndex] = aStartPoint;
2314                 mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_NORMAL;
2315                 nArrayInsert++;
2316 
2317                 // prepare next segment
2318                 const sal_uInt32 nNextIndex((a + 1) % nB2DLocalCount);
2319                 aBezier.setEndPoint(rPolygon.getB2DPoint(nNextIndex));
2320                 aBezier.setControlPointA(rPolygon.getNextControlPoint(a));
2321                 aBezier.setControlPointB(rPolygon.getPrevControlPoint(nNextIndex));
2322 
2323                 if(aBezier.isBezier())
2324                 {
2325                     // if one is used, add always two control points due to the old schema
2326                     mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointA().getX()), FRound(aBezier.getControlPointA().getY()));
2327                     mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
2328                     nArrayInsert++;
2329 
2330                     mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointB().getX()), FRound(aBezier.getControlPointB().getY()));
2331                     mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
2332                     nArrayInsert++;
2333                 }
2334 
2335                 // test continuity with previous control point to set flag value
2336                 if(aBezier.getControlPointA() != aBezier.getStartPoint() && (bClosed || a))
2337                 {
2338                     const basegfx::B2VectorContinuity eCont(rPolygon.getContinuityInPoint(a));
2339 
2340                     if(basegfx::CONTINUITY_C1 == eCont)
2341                     {
2342                         mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SMOOTH;
2343                     }
2344                     else if(basegfx::CONTINUITY_C2 == eCont)
2345                     {
2346                         mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SYMMTR;
2347                     }
2348                 }
2349 
2350                 // prepare next polygon step
2351                 aBezier.setStartPoint(aBezier.getEndPoint());
2352             }
2353 
2354             if(bClosed)
2355             {
2356                 // add first point again as closing point due to old definition
2357                 mpImplPolygon->mpPointAry[nArrayInsert] = mpImplPolygon->mpPointAry[0];
2358                 mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
2359                 nArrayInsert++;
2360             }
2361             else
2362             {
2363                 // add last point as closing point
2364                 const basegfx::B2DPoint aClosingPoint(rPolygon.getB2DPoint(nB2DLocalCount - 1L));
2365                 const Point aEnd(FRound(aClosingPoint.getX()), FRound(aClosingPoint.getY()));
2366                 mpImplPolygon->mpPointAry[nArrayInsert] = aEnd;
2367                 mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
2368                 nArrayInsert++;
2369             }
2370 
2371             DBG_ASSERT(nArrayInsert <= nMaxTargetCount, "Polygon::Polygon from basegfx::B2DPolygon: wrong max point count estimation (!)");
2372 
2373             if(nArrayInsert != nMaxTargetCount)
2374             {
2375                 mpImplPolygon->ImplSetSize(static_cast< sal_uInt16 >(nArrayInsert), true);
2376             }
2377         }
2378     }
2379     else
2380     {
2381         // #127979# Reduce source point count hard to the limit of the tools Polygon
2382         if(nB2DLocalCount > (0x0000ffff - 1L))
2383         {
2384             DBG_ERROR("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
2385             nB2DLocalCount = (0x0000ffff - 1L);
2386         }
2387 
2388         if(nB2DLocalCount)
2389         {
2390             // point list creation
2391             const sal_uInt32 nTargetCount(nB2DLocalCount + (bClosed ? 1L : 0L));
2392             mpImplPolygon = new ImplPolygon( static_cast< sal_uInt16 >(nTargetCount) );
2393             sal_uInt16 nIndex(0);
2394 
2395             for(sal_uInt32 a(0L); a < nB2DLocalCount; a++)
2396             {
2397                 basegfx::B2DPoint aB2DPoint(rPolygon.getB2DPoint(a));
2398                 Point aPoint(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY()));
2399                 mpImplPolygon->mpPointAry[nIndex++] = aPoint;
2400             }
2401 
2402             if(bClosed)
2403             {
2404                 // add first point as closing point
2405                 mpImplPolygon->mpPointAry[nIndex] = mpImplPolygon->mpPointAry[0];
2406             }
2407         }
2408     }
2409 
2410     if(!mpImplPolygon)
2411     {
2412         // no content yet, create empty polygon
2413         mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
2414     }
2415 }
2416 
2417 // eof
2418