fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / tools / source / generic / poly.cxx
blob457a05b4d11256abb0c90467f240aac3f9602550
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <osl/endian.h>
21 #include <osl/diagnose.h>
22 #include <sal/log.hxx>
23 #include <tools/bigint.hxx>
24 #include <tools/debug.hxx>
25 #include <tools/helpers.hxx>
26 #include <tools/stream.hxx>
27 #include <tools/vcompat.hxx>
28 #include <tools/gen.hxx>
29 #include <poly.h>
30 #include <tools/line.hxx>
31 #include <tools/vector2d.hxx>
32 #include <tools/poly.hxx>
33 #include <basegfx/polygon/b2dpolygon.hxx>
34 #include <basegfx/point/b2dpoint.hxx>
35 #include <basegfx/vector/b2dvector.hxx>
36 #include <basegfx/polygon/b2dpolygontools.hxx>
37 #include <basegfx/curve/b2dcubicbezier.hxx>
39 #include <memory>
40 #include <vector>
41 #include <iterator>
42 #include <algorithm>
43 #include <cstring>
44 #include <limits.h>
45 #include <cmath>
47 #define EDGE_LEFT 1
48 #define EDGE_TOP 2
49 #define EDGE_RIGHT 4
50 #define EDGE_BOTTOM 8
51 #define EDGE_HORZ (EDGE_RIGHT | EDGE_LEFT)
52 #define EDGE_VERT (EDGE_TOP | EDGE_BOTTOM)
53 #define SMALL_DVALUE 0.0000001
54 #define FSQRT2 1.4142135623730950488016887242097
56 static ImplPolygonData aStaticImplPolygon =
58 NULL, NULL, 0, 0
61 ImplPolygon::ImplPolygon( sal_uInt16 nInitSize, bool bFlags )
63 if ( nInitSize )
65 mpPointAry = reinterpret_cast<Point*>(new char[(sal_uIntPtr)nInitSize*sizeof(Point)]);
66 memset( mpPointAry, 0, (sal_uIntPtr)nInitSize*sizeof(Point) );
68 else
69 mpPointAry = NULL;
71 if( bFlags )
73 mpFlagAry = new sal_uInt8[ nInitSize ];
74 memset( mpFlagAry, 0, nInitSize );
76 else
77 mpFlagAry = NULL;
79 mnRefCount = 1;
80 mnPoints = nInitSize;
83 ImplPolygon::ImplPolygon( const ImplPolygon& rImpPoly )
85 if ( rImpPoly.mnPoints )
87 mpPointAry = reinterpret_cast<Point*>(new char[(sal_uIntPtr)rImpPoly.mnPoints*sizeof(Point)]);
88 memcpy( mpPointAry, rImpPoly.mpPointAry, (sal_uIntPtr)rImpPoly.mnPoints*sizeof(Point) );
90 if( rImpPoly.mpFlagAry )
92 mpFlagAry = new sal_uInt8[ rImpPoly.mnPoints ];
93 memcpy( mpFlagAry, rImpPoly.mpFlagAry, rImpPoly.mnPoints );
95 else
96 mpFlagAry = NULL;
98 else
100 mpPointAry = NULL;
101 mpFlagAry = NULL;
104 mnRefCount = 1;
105 mnPoints = rImpPoly.mnPoints;
108 ImplPolygon::ImplPolygon( sal_uInt16 nInitSize, const Point* pInitAry, const sal_uInt8* pInitFlags )
110 if ( nInitSize )
112 mpPointAry = reinterpret_cast<Point*>(new char[(sal_uIntPtr)nInitSize*sizeof(Point)]);
113 memcpy( mpPointAry, pInitAry, (sal_uIntPtr)nInitSize*sizeof( Point ) );
115 if( pInitFlags )
117 mpFlagAry = new sal_uInt8[ nInitSize ];
118 memcpy( mpFlagAry, pInitFlags, nInitSize );
120 else
121 mpFlagAry = NULL;
123 else
125 mpPointAry = NULL;
126 mpFlagAry = NULL;
129 mnRefCount = 1;
130 mnPoints = nInitSize;
133 ImplPolygon::~ImplPolygon()
135 if ( mpPointAry )
137 delete[] reinterpret_cast<char*>(mpPointAry);
140 if( mpFlagAry )
141 delete[] mpFlagAry;
144 void ImplPolygon::ImplSetSize( sal_uInt16 nNewSize, bool bResize )
146 if( mnPoints == nNewSize )
147 return;
149 Point* pNewAry;
151 if ( nNewSize )
153 pNewAry = reinterpret_cast<Point*>(new char[(sal_uIntPtr)nNewSize*sizeof(Point)]);
155 if ( bResize )
157 // Copy the old points
158 if ( mnPoints < nNewSize )
160 // New points initialized to zero
161 memset( pNewAry+mnPoints, 0, (sal_uIntPtr)(nNewSize-mnPoints)*sizeof(Point) );
162 if ( mpPointAry )
163 memcpy( pNewAry, mpPointAry, mnPoints*sizeof(Point) );
165 else
167 if ( mpPointAry )
168 memcpy( pNewAry, mpPointAry, (sal_uIntPtr)nNewSize*sizeof(Point) );
172 else
173 pNewAry = NULL;
175 if ( mpPointAry )
176 delete[] reinterpret_cast<char*>(mpPointAry);
178 // ggf. FlagArray beruecksichtigen
179 if( mpFlagAry )
181 sal_uInt8* pNewFlagAry;
183 if( nNewSize )
185 pNewFlagAry = new sal_uInt8[ nNewSize ];
187 if( bResize )
189 // copy the old flags
190 if ( mnPoints < nNewSize )
192 // initialize new flags to zero
193 memset( pNewFlagAry+mnPoints, 0, nNewSize-mnPoints );
194 memcpy( pNewFlagAry, mpFlagAry, mnPoints );
196 else
197 memcpy( pNewFlagAry, mpFlagAry, nNewSize );
200 else
201 pNewFlagAry = NULL;
203 delete[] mpFlagAry;
204 mpFlagAry = pNewFlagAry;
207 mpPointAry = pNewAry;
208 mnPoints = nNewSize;
211 void ImplPolygon::ImplSplit( sal_uInt16 nPos, sal_uInt16 nSpace, ImplPolygon* pInitPoly )
213 const sal_uIntPtr nSpaceSize = nSpace * sizeof( Point );
215 //Can't fit this in :-(, throw ?
216 if (mnPoints + nSpace > USHRT_MAX)
217 return;
219 const sal_uInt16 nNewSize = mnPoints + nSpace;
221 if( nPos >= mnPoints )
223 // Append at the back
224 nPos = mnPoints;
225 ImplSetSize( nNewSize, true );
227 if( pInitPoly )
229 memcpy( mpPointAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
231 if( pInitPoly->mpFlagAry )
232 memcpy( mpFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
235 else
237 const sal_uInt16 nSecPos = nPos + nSpace;
238 const sal_uInt16 nRest = mnPoints - nPos;
240 Point* pNewAry = reinterpret_cast<Point*>(new char[ (sal_uIntPtr) nNewSize * sizeof( Point ) ]);
242 memcpy( pNewAry, mpPointAry, nPos * sizeof( Point ) );
244 if( pInitPoly )
245 memcpy( pNewAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
246 else
247 memset( pNewAry + nPos, 0, nSpaceSize );
249 memcpy( pNewAry + nSecPos, mpPointAry + nPos, nRest * sizeof( Point ) );
250 delete[] reinterpret_cast<char*>(mpPointAry);
252 // consider FlagArray
253 if( mpFlagAry )
255 sal_uInt8* pNewFlagAry = new sal_uInt8[ nNewSize ];
257 memcpy( pNewFlagAry, mpFlagAry, nPos );
259 if( pInitPoly && pInitPoly->mpFlagAry )
260 memcpy( pNewFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
261 else
262 memset( pNewFlagAry + nPos, 0, nSpace );
264 memcpy( pNewFlagAry + nSecPos, mpFlagAry + nPos, nRest );
265 delete[] mpFlagAry;
266 mpFlagAry = pNewFlagAry;
269 mpPointAry = pNewAry;
270 mnPoints = nNewSize;
274 void ImplPolygon::ImplCreateFlagArray()
276 if( !mpFlagAry )
278 mpFlagAry = new sal_uInt8[ mnPoints ];
279 memset( mpFlagAry, 0, mnPoints );
284 Polygon Polygon::SubdivideBezier( const Polygon& rPoly )
286 Polygon aPoly;
288 // #100127# Use adaptive subdivide instead of fixed 25 segments
289 rPoly.AdaptiveSubdivide( aPoly );
291 return aPoly;
295 inline void Polygon::ImplMakeUnique()
297 // copy references if any exist
298 if ( mpImplPolygon->mnRefCount != 1 )
300 if ( mpImplPolygon->mnRefCount )
301 mpImplPolygon->mnRefCount--;
302 mpImplPolygon = new ImplPolygon( *mpImplPolygon );
306 inline double ImplGetParameter( const Point& rCenter, const Point& rPt, double fWR, double fHR )
308 const long nDX = rPt.X() - rCenter.X();
309 double fAngle = atan2( -rPt.Y() + rCenter.Y(), ( ( nDX == 0L ) ? 0.000000001 : nDX ) );
311 return atan2(fWR*sin(fAngle), fHR*cos(fAngle));
314 Polygon::Polygon()
316 mpImplPolygon = static_cast<ImplPolygon*>(&aStaticImplPolygon);
319 Polygon::Polygon( sal_uInt16 nSize )
322 if ( nSize )
323 mpImplPolygon = new ImplPolygon( nSize );
324 else
325 mpImplPolygon = static_cast<ImplPolygon*>(&aStaticImplPolygon);
328 Polygon::Polygon( sal_uInt16 nPoints, const Point* pPtAry, const sal_uInt8* pFlagAry )
331 if( nPoints )
332 mpImplPolygon = new ImplPolygon( nPoints, pPtAry, pFlagAry );
333 else
334 mpImplPolygon = static_cast<ImplPolygon*>(&aStaticImplPolygon);
337 Polygon::Polygon( const Polygon& rPoly )
339 DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
341 mpImplPolygon = rPoly.mpImplPolygon;
342 if ( mpImplPolygon->mnRefCount )
343 mpImplPolygon->mnRefCount++;
346 Polygon::Polygon( const Rectangle& rRect )
349 if ( rRect.IsEmpty() )
350 mpImplPolygon = static_cast<ImplPolygon*>(&aStaticImplPolygon);
351 else
353 mpImplPolygon = new ImplPolygon( 5 );
354 mpImplPolygon->mpPointAry[0] = rRect.TopLeft();
355 mpImplPolygon->mpPointAry[1] = rRect.TopRight();
356 mpImplPolygon->mpPointAry[2] = rRect.BottomRight();
357 mpImplPolygon->mpPointAry[3] = rRect.BottomLeft();
358 mpImplPolygon->mpPointAry[4] = rRect.TopLeft();
362 Polygon::Polygon( const Rectangle& rRect, sal_uIntPtr nHorzRound, sal_uIntPtr nVertRound )
364 if ( rRect.IsEmpty() )
365 mpImplPolygon = static_cast<ImplPolygon*>(&aStaticImplPolygon);
366 else
368 Rectangle aRect( rRect );
369 aRect.Justify(); // SJ: i9140
371 nHorzRound = std::min( nHorzRound, (sal_uIntPtr) labs( aRect.GetWidth() >> 1 ) );
372 nVertRound = std::min( nVertRound, (sal_uIntPtr) labs( aRect.GetHeight() >> 1 ) );
374 if( !nHorzRound && !nVertRound )
376 mpImplPolygon = new ImplPolygon( 5 );
377 mpImplPolygon->mpPointAry[0] = aRect.TopLeft();
378 mpImplPolygon->mpPointAry[1] = aRect.TopRight();
379 mpImplPolygon->mpPointAry[2] = aRect.BottomRight();
380 mpImplPolygon->mpPointAry[3] = aRect.BottomLeft();
381 mpImplPolygon->mpPointAry[4] = aRect.TopLeft();
383 else
385 const Point aTL( aRect.Left() + nHorzRound, aRect.Top() + nVertRound );
386 const Point aTR( aRect.Right() - nHorzRound, aRect.Top() + nVertRound );
387 const Point aBR( aRect.Right() - nHorzRound, aRect.Bottom() - nVertRound );
388 const Point aBL( aRect.Left() + nHorzRound, aRect.Bottom() - nVertRound );
389 Polygon* pEllipsePoly = new Polygon( Point(), nHorzRound, nVertRound );
390 sal_uInt16 i, nEnd, nSize4 = pEllipsePoly->GetSize() >> 2;
392 mpImplPolygon = new ImplPolygon( pEllipsePoly->GetSize() + 1 );
394 const Point* pSrcAry = pEllipsePoly->GetConstPointAry();
395 Point* pDstAry = mpImplPolygon->mpPointAry;
397 for( i = 0, nEnd = nSize4; i < nEnd; i++ )
398 ( pDstAry[ i ] = pSrcAry[ i ] ) += aTR;
400 for( nEnd = nEnd + nSize4; i < nEnd; i++ )
401 ( pDstAry[ i ] = pSrcAry[ i ] ) += aTL;
403 for( nEnd = nEnd + nSize4; i < nEnd; i++ )
404 ( pDstAry[ i ] = pSrcAry[ i ] ) += aBL;
406 for( nEnd = nEnd + nSize4; i < nEnd; i++ )
407 ( pDstAry[ i ] = pSrcAry[ i ] ) += aBR;
409 pDstAry[ nEnd ] = pDstAry[ 0 ];
410 delete pEllipsePoly;
415 Polygon::Polygon( const Point& rCenter, long nRadX, long nRadY, sal_uInt16 nPoints )
417 if( nRadX && nRadY )
419 // Compute default (depends on size)
420 if( !nPoints )
422 nPoints = (sal_uInt16) MinMax(
423 ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
424 sqrt( (double) labs( nRadX * nRadY ) ) ) ),
425 32, 256 );
427 if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
428 nPoints >>= 1;
431 // Ceil number of points until divisible by four
432 mpImplPolygon = new ImplPolygon( nPoints = (nPoints + 3) & ~3 );
434 Point* pPt;
435 sal_uInt16 i;
436 sal_uInt16 nPoints2 = nPoints >> 1;
437 sal_uInt16 nPoints4 = nPoints >> 2;
438 double nAngle;
439 double nAngleStep = F_PI2 / ( nPoints4 - 1 );
441 for( i=0, nAngle = 0.0; i < nPoints4; i++, nAngle += nAngleStep )
443 long nX = FRound( nRadX * cos( nAngle ) );
444 long nY = FRound( -nRadY * sin( nAngle ) );
446 pPt = &(mpImplPolygon->mpPointAry[i]);
447 pPt->X() = nX + rCenter.X();
448 pPt->Y() = nY + rCenter.Y();
449 pPt = &(mpImplPolygon->mpPointAry[nPoints2-i-1]);
450 pPt->X() = -nX + rCenter.X();
451 pPt->Y() = nY + rCenter.Y();
452 pPt = &(mpImplPolygon->mpPointAry[i+nPoints2]);
453 pPt->X() = -nX + rCenter.X();
454 pPt->Y() = -nY + rCenter.Y();
455 pPt = &(mpImplPolygon->mpPointAry[nPoints-i-1]);
456 pPt->X() = nX + rCenter.X();
457 pPt->Y() = -nY + rCenter.Y();
460 else
461 mpImplPolygon = static_cast<ImplPolygon*>(&aStaticImplPolygon);
464 Polygon::Polygon( const Rectangle& rBound, const Point& rStart, const Point& rEnd,
465 PolyStyle eStyle, bool bFullCircle )
467 const long nWidth = rBound.GetWidth();
468 const long nHeight = rBound.GetHeight();
470 if( ( nWidth > 1 ) && ( nHeight > 1 ) )
472 const Point aCenter( rBound.Center() );
473 const long nRadX = aCenter.X() - rBound.Left();
474 const long nRadY = aCenter.Y() - rBound.Top();
475 sal_uInt16 nPoints;
477 nPoints = (sal_uInt16) MinMax(
478 ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
479 sqrt( (double) labs( nRadX * nRadY ) ) ) ),
480 32, 256 );
482 if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
483 nPoints >>= 1;
485 // compute threshold
486 const double fRadX = nRadX;
487 const double fRadY = nRadY;
488 const double fCenterX = aCenter.X();
489 const double fCenterY = aCenter.Y();
490 double fStart = ImplGetParameter( aCenter, rStart, fRadX, fRadY );
491 double fEnd = ImplGetParameter( aCenter, rEnd, fRadX, fRadY );
492 double fDiff = fEnd - fStart;
493 double fStep;
494 sal_uInt16 nStart;
495 sal_uInt16 nEnd;
497 if( fDiff < 0. )
498 fDiff += F_2PI;
500 if ( bFullCircle )
501 fDiff = F_2PI;
503 // Proportionally shrink number of points( fDiff / (2PI) );
504 nPoints = std::max( (sal_uInt16) ( ( fDiff * 0.1591549 ) * nPoints ), (sal_uInt16) 16 );
505 fStep = fDiff / ( nPoints - 1 );
507 if( POLY_PIE == eStyle )
509 const Point aCenter2( FRound( fCenterX ), FRound( fCenterY ) );
511 nStart = 1;
512 nEnd = nPoints + 1;
513 mpImplPolygon = new ImplPolygon( nPoints + 2 );
514 mpImplPolygon->mpPointAry[ 0 ] = aCenter2;
515 mpImplPolygon->mpPointAry[ nEnd ] = aCenter2;
517 else
519 mpImplPolygon = new ImplPolygon( ( POLY_CHORD == eStyle ) ? ( nPoints + 1 ) : nPoints );
520 nStart = 0;
521 nEnd = nPoints;
524 for(; nStart < nEnd; nStart++, fStart += fStep )
526 Point& rPt = mpImplPolygon->mpPointAry[ nStart ];
528 rPt.X() = FRound( fCenterX + fRadX * cos( fStart ) );
529 rPt.Y() = FRound( fCenterY - fRadY * sin( fStart ) );
532 if( POLY_CHORD == eStyle )
533 mpImplPolygon->mpPointAry[ nPoints ] = mpImplPolygon->mpPointAry[ 0 ];
535 else
536 mpImplPolygon = static_cast<ImplPolygon*>( &aStaticImplPolygon );
539 Polygon::Polygon( const Point& rBezPt1, const Point& rCtrlPt1,
540 const Point& rBezPt2, const Point& rCtrlPt2,
541 sal_uInt16 nPoints )
543 nPoints = ( 0 == nPoints ) ? 25 : ( ( nPoints < 2 ) ? 2 : nPoints );
545 const double fInc = 1.0 / ( nPoints - 1 );
546 double fK_1 = 0.0, fK1_1 = 1.0;
547 double fK_2, fK_3, fK1_2, fK1_3, fK12, fK21;
548 const double fX0 = rBezPt1.X();
549 const double fY0 = rBezPt1.Y();
550 const double fX1 = 3.0 * rCtrlPt1.X();
551 const double fY1 = 3.0 * rCtrlPt1.Y();
552 const double fX2 = 3.0 * rCtrlPt2.X();
553 const double fY2 = 3.0 * rCtrlPt2.Y();
554 const double fX3 = rBezPt2.X();
555 const double fY3 = rBezPt2.Y();
557 mpImplPolygon = new ImplPolygon( nPoints );
559 for( sal_uInt16 i = 0; i < nPoints; i++, fK_1 += fInc, fK1_1 -= fInc )
561 Point& rPt = mpImplPolygon->mpPointAry[ i ];
563 fK_2 = fK_1, fK_3 = ( fK_2 *= fK_1 ), fK_3 *= fK_1;
564 fK1_2 = fK1_1, fK1_3 = ( fK1_2 *= fK1_1 ), fK1_3 *= fK1_1;
565 fK12 = fK_1 * fK1_2, fK21 = fK_2 * fK1_1;
567 rPt.X() = FRound( fK1_3 * fX0 + fK12 * fX1 + fK21 * fX2 + fK_3 * fX3 );
568 rPt.Y() = FRound( fK1_3 * fY0 + fK12 * fY1 + fK21 * fY2 + fK_3 * fY3 );
572 Polygon::~Polygon()
575 // Remove if refcount == 0, otherwise decrement refcount
576 if ( mpImplPolygon->mnRefCount )
578 if ( mpImplPolygon->mnRefCount > 1 )
579 mpImplPolygon->mnRefCount--;
580 else
581 delete mpImplPolygon;
585 const Point* Polygon::GetConstPointAry() const
587 return mpImplPolygon->mpPointAry;
590 const sal_uInt8* Polygon::GetConstFlagAry() const
592 return mpImplPolygon->mpFlagAry;
595 void Polygon::SetPoint( const Point& rPt, sal_uInt16 nPos )
597 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
598 "Polygon::SetPoint(): nPos >= nPoints" );
600 ImplMakeUnique();
601 mpImplPolygon->mpPointAry[nPos] = rPt;
604 void Polygon::SetFlags( sal_uInt16 nPos, PolyFlags eFlags )
606 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
607 "Polygon::SetFlags(): nPos >= nPoints" );
609 // we do only want to create the flag array if there
610 // is at least one flag different to POLY_NORMAL
611 if ( eFlags != POLY_NORMAL )
613 ImplMakeUnique();
614 mpImplPolygon->ImplCreateFlagArray();
615 mpImplPolygon->mpFlagAry[ nPos ] = (sal_uInt8) eFlags;
619 const Point& Polygon::GetPoint( sal_uInt16 nPos ) const
621 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
622 "Polygon::GetPoint(): nPos >= nPoints" );
624 return mpImplPolygon->mpPointAry[nPos];
627 PolyFlags Polygon::GetFlags( sal_uInt16 nPos ) const
629 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
630 "Polygon::GetFlags(): nPos >= nPoints" );
631 return( mpImplPolygon->mpFlagAry ?
632 (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] :
633 POLY_NORMAL );
636 bool Polygon::HasFlags() const
638 return mpImplPolygon->mpFlagAry != NULL;
641 bool Polygon::IsRect() const
643 bool bIsRect = false;
644 if ( mpImplPolygon->mpFlagAry == NULL )
646 if ( ( ( mpImplPolygon->mnPoints == 5 ) && ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ 4 ] ) ) ||
647 ( mpImplPolygon->mnPoints == 4 ) )
649 if ( ( mpImplPolygon->mpPointAry[ 0 ].X() == mpImplPolygon->mpPointAry[ 3 ].X() ) &&
650 ( mpImplPolygon->mpPointAry[ 0 ].Y() == mpImplPolygon->mpPointAry[ 1 ].Y() ) &&
651 ( mpImplPolygon->mpPointAry[ 1 ].X() == mpImplPolygon->mpPointAry[ 2 ].X() ) &&
652 ( mpImplPolygon->mpPointAry[ 2 ].Y() == mpImplPolygon->mpPointAry[ 3 ].Y() ) )
653 bIsRect = true;
656 return bIsRect;
659 void Polygon::SetSize( sal_uInt16 nNewSize )
661 if( nNewSize != mpImplPolygon->mnPoints )
663 ImplMakeUnique();
664 mpImplPolygon->ImplSetSize( nNewSize );
668 sal_uInt16 Polygon::GetSize() const
670 return mpImplPolygon->mnPoints;
673 void Polygon::Clear()
675 if ( mpImplPolygon->mnRefCount )
677 if ( mpImplPolygon->mnRefCount > 1 )
678 mpImplPolygon->mnRefCount--;
679 else
680 delete mpImplPolygon;
683 mpImplPolygon = static_cast<ImplPolygon*>(&aStaticImplPolygon);
686 double Polygon::CalcDistance( sal_uInt16 nP1, sal_uInt16 nP2 )
688 DBG_ASSERT( nP1 < mpImplPolygon->mnPoints,
689 "Polygon::CalcDistance(): nPos1 >= nPoints" );
690 DBG_ASSERT( nP2 < mpImplPolygon->mnPoints,
691 "Polygon::CalcDistance(): nPos2 >= nPoints" );
693 const Point& rP1 = mpImplPolygon->mpPointAry[ nP1 ];
694 const Point& rP2 = mpImplPolygon->mpPointAry[ nP2 ];
695 const double fDx = rP2.X() - rP1.X();
696 const double fDy = rP2.Y() - rP1.Y();
698 return sqrt( fDx * fDx + fDy * fDy );
701 void Polygon::Optimize( PolyOptimizeFlags nOptimizeFlags, const PolyOptimizeData* pData )
703 DBG_ASSERT( !mpImplPolygon->mpFlagAry, "Optimizing could fail with beziers!" );
705 sal_uInt16 nSize = mpImplPolygon->mnPoints;
707 if( bool(nOptimizeFlags) && nSize )
709 if( nOptimizeFlags & PolyOptimizeFlags::EDGES )
711 const Rectangle aBound( GetBoundRect() );
712 const double fArea = ( aBound.GetWidth() + aBound.GetHeight() ) * 0.5;
713 const sal_uInt16 nPercent = pData ? pData->GetPercentValue() : 50;
715 Optimize( PolyOptimizeFlags::NO_SAME );
716 ImplReduceEdges( *this, fArea, nPercent );
718 else if( nOptimizeFlags & ( PolyOptimizeFlags::REDUCE | PolyOptimizeFlags::NO_SAME ) )
720 Polygon aNewPoly;
721 const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
722 sal_uIntPtr nReduce;
724 if( nOptimizeFlags & ( PolyOptimizeFlags::REDUCE ) )
725 nReduce = pData ? pData->GetAbsValue() : 4UL;
726 else
727 nReduce = 0UL;
729 while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
730 nSize--;
732 if( nSize > 1 )
734 sal_uInt16 nLast = 0, nNewCount = 1;
736 aNewPoly.SetSize( nSize );
737 aNewPoly[ 0 ] = rFirst;
739 for( sal_uInt16 i = 1; i < nSize; i++ )
741 if( ( mpImplPolygon->mpPointAry[ i ] != mpImplPolygon->mpPointAry[ nLast ] ) &&
742 ( !nReduce || ( nReduce < (sal_uIntPtr) FRound( CalcDistance( nLast, i ) ) ) ) )
744 aNewPoly[ nNewCount++ ] = mpImplPolygon->mpPointAry[ nLast = i ];
748 if( nNewCount == 1 )
749 aNewPoly.Clear();
750 else
751 aNewPoly.SetSize( nNewCount );
754 *this = aNewPoly;
757 nSize = mpImplPolygon->mnPoints;
759 if( nSize > 1 )
761 if( ( nOptimizeFlags & PolyOptimizeFlags::CLOSE ) &&
762 ( mpImplPolygon->mpPointAry[ 0 ] != mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
764 SetSize( mpImplPolygon->mnPoints + 1 );
765 mpImplPolygon->mpPointAry[ mpImplPolygon->mnPoints - 1 ] = mpImplPolygon->mpPointAry[ 0 ];
767 else if( ( nOptimizeFlags & PolyOptimizeFlags::OPEN ) &&
768 ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
770 const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
772 while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
773 nSize--;
775 SetSize( nSize );
782 /** Recursively subdivide cubic bezier curve via deCasteljau.
784 @param rPointIter
785 Output iterator, where the subdivided polylines are written to.
787 @param d
788 Squared difference of curve to a straight line
790 @param P*
791 Exactly four points, interpreted as support and control points of
792 a cubic bezier curve. Must be in device coordinates, since stop
793 criterion is based on the following assumption: the device has a
794 finite resolution, it is thus sufficient to stop subdivision if the
795 curve does not deviate more than one pixel from a straight line.
798 static void ImplAdaptiveSubdivide( ::std::back_insert_iterator< ::std::vector< Point > >& rPointIter,
799 const double old_d2,
800 int recursionDepth,
801 const double d2,
802 const double P1x, const double P1y,
803 const double P2x, const double P2y,
804 const double P3x, const double P3y,
805 const double P4x, const double P4y )
807 // Hard limit on recursion depth, empiric number.
808 enum {maxRecursionDepth=128};
810 // Perform bezier flatness test (lecture notes from R. Schaback,
811 // Mathematics of Computer-Aided Design, Uni Goettingen, 2000)
813 // ||P(t) - L(t)|| <= max ||b_j - b_0 - j/n(b_n - b_0)||
814 // 0<=j<=n
816 // What is calculated here is an upper bound to the distance from
817 // a line through b_0 and b_3 (P1 and P4 in our notation) and the
818 // curve. We can drop 0 and n from the running indices, since the
819 // argument of max becomes zero for those cases.
820 const double fJ1x( P2x - P1x - 1.0/3.0*(P4x - P1x) );
821 const double fJ1y( P2y - P1y - 1.0/3.0*(P4y - P1y) );
822 const double fJ2x( P3x - P1x - 2.0/3.0*(P4x - P1x) );
823 const double fJ2y( P3y - P1y - 2.0/3.0*(P4y - P1y) );
824 const double distance2( ::std::max( fJ1x*fJ1x + fJ1y*fJ1y,
825 fJ2x*fJ2x + fJ2y*fJ2y) );
827 // stop if error measure does not improve anymore. This is a
828 // safety guard against floating point inaccuracies.
829 // stop at recursion level 128. This is a safety guard against
830 // floating point inaccuracies.
831 // stop if distance from line is guaranteed to be bounded by d
832 if( old_d2 > d2 &&
833 recursionDepth < maxRecursionDepth &&
834 distance2 >= d2 )
836 // deCasteljau bezier arc, split at t=0.5
837 // Foley/vanDam, p. 508
838 const double L1x( P1x ), L1y( P1y );
839 const double L2x( (P1x + P2x)*0.5 ), L2y( (P1y + P2y)*0.5 );
840 const double Hx ( (P2x + P3x)*0.5 ), Hy ( (P2y + P3y)*0.5 );
841 const double L3x( (L2x + Hx)*0.5 ), L3y( (L2y + Hy)*0.5 );
842 const double R4x( P4x ), R4y( P4y );
843 const double R3x( (P3x + P4x)*0.5 ), R3y( (P3y + P4y)*0.5 );
844 const double R2x( (Hx + R3x)*0.5 ), R2y( (Hy + R3y)*0.5 );
845 const double R1x( (L3x + R2x)*0.5 ), R1y( (L3y + R2y)*0.5 );
846 const double L4x( R1x ), L4y( R1y );
848 // subdivide further
849 ++recursionDepth;
850 ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, L1x, L1y, L2x, L2y, L3x, L3y, L4x, L4y);
851 ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, R1x, R1y, R2x, R2y, R3x, R3y, R4x, R4y);
853 else
855 // requested resolution reached.
856 // Add end points to output iterator.
857 // order is preserved, since this is so to say depth first traversal.
858 *rPointIter++ = Point( FRound(P1x), FRound(P1y) );
862 void Polygon::AdaptiveSubdivide( Polygon& rResult, const double d ) const
864 if( !mpImplPolygon->mpFlagAry )
866 rResult = *this;
868 else
870 sal_uInt16 i;
871 sal_uInt16 nPts( GetSize() );
872 ::std::vector< Point > aPoints;
873 aPoints.reserve( nPts );
874 ::std::back_insert_iterator< ::std::vector< Point > > aPointIter( aPoints );
876 for(i=0; i<nPts;)
878 if( ( i + 3 ) < nPts )
880 sal_uInt8 P1( mpImplPolygon->mpFlagAry[ i ] );
881 sal_uInt8 P4( mpImplPolygon->mpFlagAry[ i + 3 ] );
883 if( ( POLY_NORMAL == P1 || POLY_SMOOTH == P1 || POLY_SYMMTR == P1 ) &&
884 ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 1 ] ) &&
885 ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 2 ] ) &&
886 ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
888 ImplAdaptiveSubdivide( aPointIter, d*d+1.0, 0, d*d,
889 mpImplPolygon->mpPointAry[ i ].X(), mpImplPolygon->mpPointAry[ i ].Y(),
890 mpImplPolygon->mpPointAry[ i+1 ].X(), mpImplPolygon->mpPointAry[ i+1 ].Y(),
891 mpImplPolygon->mpPointAry[ i+2 ].X(), mpImplPolygon->mpPointAry[ i+2 ].Y(),
892 mpImplPolygon->mpPointAry[ i+3 ].X(), mpImplPolygon->mpPointAry[ i+3 ].Y() );
893 i += 3;
894 continue;
898 *aPointIter++ = mpImplPolygon->mpPointAry[ i++ ];
900 if (aPoints.size() >= SAL_MAX_UINT16)
902 OSL_ENSURE(aPoints.size() < SAL_MAX_UINT16,
903 "Polygon::AdapativeSubdivision created polygon too many points;"
904 " using original polygon instead");
906 // The resulting polygon can not hold all the points
907 // that we have created so far. Stop the subdivision
908 // and return a copy of the unmodified polygon.
909 rResult = *this;
910 return;
914 // fill result polygon
915 rResult = Polygon( (sal_uInt16)aPoints.size() ); // ensure sufficient size for copy
916 ::std::copy(aPoints.begin(), aPoints.end(), rResult.mpImplPolygon->mpPointAry);
920 void Polygon::ImplReduceEdges( Polygon& rPoly, const double& rArea, sal_uInt16 nPercent )
922 const double fBound = 2000.0 * ( 100 - nPercent ) * 0.01;
923 sal_uInt16 nNumNoChange = 0,
924 nNumRuns = 0;
926 while( nNumNoChange < 2 )
928 sal_uInt16 nPntCnt = rPoly.GetSize(), nNewPos = 0;
929 Polygon aNewPoly( nPntCnt );
930 bool bChangeInThisRun = false;
932 for( sal_uInt16 n = 0; n < nPntCnt; n++ )
934 bool bDeletePoint = false;
936 if( ( n + nNumRuns ) % 2 )
938 sal_uInt16 nIndPrev = !n ? nPntCnt - 1 : n - 1;
939 sal_uInt16 nIndPrevPrev = !nIndPrev ? nPntCnt - 1 : nIndPrev - 1;
940 sal_uInt16 nIndNext = ( n == nPntCnt-1 ) ? 0 : n + 1;
941 sal_uInt16 nIndNextNext = ( nIndNext == nPntCnt - 1 ) ? 0 : nIndNext + 1;
942 Vector2D aVec1( rPoly[ nIndPrev ] ); aVec1 -= rPoly[ nIndPrevPrev ];
943 Vector2D aVec2( rPoly[ n ] ); aVec2 -= rPoly[ nIndPrev ];
944 Vector2D aVec3( rPoly[ nIndNext ] ); aVec3 -= rPoly[ n ];
945 Vector2D aVec4( rPoly[ nIndNextNext ] ); aVec4 -= rPoly[ nIndNext ];
946 double fDist1 = aVec1.GetLength(), fDist2 = aVec2.GetLength();
947 double fDist3 = aVec3.GetLength(), fDist4 = aVec4.GetLength();
948 double fTurnB = aVec2.Normalize().Scalar( aVec3.Normalize() );
950 if( fabs( fTurnB ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnB ) > ( 1.0 - SMALL_DVALUE ) )
951 bDeletePoint = true;
952 else
954 Vector2D aVecB( rPoly[ nIndNext ] );
955 double fDistB = ( aVecB -= rPoly[ nIndPrev ] ).GetLength();
956 double fLenWithB = fDist2 + fDist3;
957 double fLenFact = ( fDistB != 0.0 ) ? fLenWithB / fDistB : 1.0;
958 double fTurnPrev = aVec1.Normalize().Scalar( aVec2 );
959 double fTurnNext = aVec3.Scalar( aVec4.Normalize() );
960 double fGradPrev, fGradB, fGradNext;
962 if( fabs( fTurnPrev ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnPrev ) > ( 1.0 - SMALL_DVALUE ) )
963 fGradPrev = 0.0;
964 else
965 fGradPrev = acos( fTurnPrev ) / ( aVec1.IsNegative( aVec2 ) ? -F_PI180 : F_PI180 );
967 fGradB = acos( fTurnB ) / ( aVec2.IsNegative( aVec3 ) ? -F_PI180 : F_PI180 );
969 if( fabs( fTurnNext ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnNext ) > ( 1.0 - SMALL_DVALUE ) )
970 fGradNext = 0.0;
971 else
972 fGradNext = acos( fTurnNext ) / ( aVec3.IsNegative( aVec4 ) ? -F_PI180 : F_PI180 );
974 if( ( fGradPrev > 0.0 && fGradB < 0.0 && fGradNext > 0.0 ) ||
975 ( fGradPrev < 0.0 && fGradB > 0.0 && fGradNext < 0.0 ) )
977 if( ( fLenFact < ( FSQRT2 + SMALL_DVALUE ) ) &&
978 ( ( ( fDist1 + fDist4 ) / ( fDist2 + fDist3 ) ) * 2000.0 ) > fBound )
980 bDeletePoint = true;
983 else
985 double fRelLen = 1.0 - sqrt( fDistB / rArea );
987 if( fRelLen < 0.0 )
988 fRelLen = 0.0;
989 else if( fRelLen > 1.0 )
990 fRelLen = 1.0;
992 if( ( (sal_uInt32) ( ( ( fLenFact - 1.0 ) * 1000000.0 ) + 0.5 ) < fBound ) &&
993 ( fabs( fGradB ) <= ( fRelLen * fBound * 0.01 ) ) )
995 bDeletePoint = true;
1001 if( !bDeletePoint )
1002 aNewPoly[ nNewPos++ ] = rPoly[ n ];
1003 else
1004 bChangeInThisRun = true;
1007 if( bChangeInThisRun && nNewPos )
1009 aNewPoly.SetSize( nNewPos );
1010 rPoly = aNewPoly;
1011 nNumNoChange = 0;
1013 else
1014 nNumNoChange++;
1016 nNumRuns++;
1020 void Polygon::Move( long nHorzMove, long nVertMove )
1022 // This check is required for DrawEngine
1023 if ( !nHorzMove && !nVertMove )
1024 return;
1026 ImplMakeUnique();
1028 // Move points
1029 sal_uInt16 nCount = mpImplPolygon->mnPoints;
1030 for ( sal_uInt16 i = 0; i < nCount; i++ )
1032 Point* pPt = &(mpImplPolygon->mpPointAry[i]);
1033 pPt->X() += nHorzMove;
1034 pPt->Y() += nVertMove;
1038 void Polygon::Translate(const Point& rTrans)
1040 ImplMakeUnique();
1042 for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1043 mpImplPolygon->mpPointAry[ i ] += rTrans;
1046 void Polygon::Scale( double fScaleX, double fScaleY )
1048 ImplMakeUnique();
1050 for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1052 Point& rPnt = mpImplPolygon->mpPointAry[i];
1053 rPnt.X() = (long) ( fScaleX * rPnt.X() );
1054 rPnt.Y() = (long) ( fScaleY * rPnt.Y() );
1058 void Polygon::Rotate( const Point& rCenter, sal_uInt16 nAngle10 )
1060 nAngle10 %= 3600;
1062 if( nAngle10 )
1064 const double fAngle = F_PI1800 * nAngle10;
1065 Rotate( rCenter, sin( fAngle ), cos( fAngle ) );
1069 void Polygon::Rotate( const Point& rCenter, double fSin, double fCos )
1071 ImplMakeUnique();
1073 long nCenterX = rCenter.X();
1074 long nCenterY = rCenter.Y();
1076 for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1078 Point& rPt = mpImplPolygon->mpPointAry[ i ];
1080 const long nX = rPt.X() - nCenterX;
1081 const long nY = rPt.Y() - nCenterY;
1082 rPt.X() = (long) FRound( fCos * nX + fSin * nY ) + nCenterX;
1083 rPt.Y() = -(long) FRound( fSin * nX - fCos * nY ) + nCenterY;
1087 class ImplPointFilter
1089 public:
1090 virtual void LastPoint() = 0;
1091 virtual void Input( const Point& rPoint ) = 0;
1093 protected:
1094 ~ImplPointFilter() {}
1097 class ImplPolygonPointFilter : public ImplPointFilter
1099 std::unique_ptr<ImplPolygon> mxPoly;
1100 sal_uInt16 mnSize;
1101 public:
1102 ImplPolygonPointFilter(sal_uInt16 nDestSize)
1103 : mxPoly(new ImplPolygon(nDestSize))
1104 , mnSize(0)
1108 virtual ~ImplPolygonPointFilter()
1112 virtual void LastPoint() SAL_OVERRIDE;
1113 virtual void Input( const Point& rPoint ) SAL_OVERRIDE;
1115 ImplPolygon* release() { return mxPoly.release(); }
1118 void ImplPolygonPointFilter::Input( const Point& rPoint )
1120 if ( !mnSize || (rPoint != mxPoly->mpPointAry[mnSize-1]) )
1122 mnSize++;
1123 if ( mnSize > mxPoly->mnPoints )
1124 mxPoly->ImplSetSize( mnSize );
1125 mxPoly->mpPointAry[mnSize-1] = rPoint;
1129 void ImplPolygonPointFilter::LastPoint()
1131 if ( mnSize < mxPoly->mnPoints )
1132 mxPoly->ImplSetSize( mnSize );
1135 class ImplEdgePointFilter : public ImplPointFilter
1137 Point maFirstPoint;
1138 Point maLastPoint;
1139 ImplPointFilter& mrNextFilter;
1140 const long mnLow;
1141 const long mnHigh;
1142 const int mnEdge;
1143 int mnLastOutside;
1144 bool mbFirst;
1146 public:
1147 ImplEdgePointFilter( int nEdge, long nLow, long nHigh,
1148 ImplPointFilter& rNextFilter ) :
1149 mrNextFilter( rNextFilter ),
1150 mnLow( nLow ),
1151 mnHigh( nHigh ),
1152 mnEdge( nEdge ),
1153 mnLastOutside( 0 ),
1154 mbFirst( true )
1158 virtual ~ImplEdgePointFilter() {}
1160 Point EdgeSection( const Point& rPoint, int nEdge ) const;
1161 int VisibleSide( const Point& rPoint ) const;
1162 bool IsPolygon() const
1163 { return maFirstPoint == maLastPoint; }
1165 virtual void Input( const Point& rPoint ) SAL_OVERRIDE;
1166 virtual void LastPoint() SAL_OVERRIDE;
1169 inline int ImplEdgePointFilter::VisibleSide( const Point& rPoint ) const
1171 if ( mnEdge & EDGE_HORZ )
1173 return rPoint.X() < mnLow ? EDGE_LEFT :
1174 rPoint.X() > mnHigh ? EDGE_RIGHT : 0;
1176 else
1178 return rPoint.Y() < mnLow ? EDGE_TOP :
1179 rPoint.Y() > mnHigh ? EDGE_BOTTOM : 0;
1183 Point ImplEdgePointFilter::EdgeSection( const Point& rPoint, int nEdge ) const
1185 long lx = maLastPoint.X();
1186 long ly = maLastPoint.Y();
1187 long md = rPoint.X() - lx;
1188 long mn = rPoint.Y() - ly;
1189 long nNewX;
1190 long nNewY;
1192 if ( nEdge & EDGE_VERT )
1194 nNewY = (nEdge == EDGE_TOP) ? mnLow : mnHigh;
1195 long dy = nNewY - ly;
1196 if ( !md )
1197 nNewX = lx;
1198 else if ( (LONG_MAX / std::abs(md)) >= std::abs(dy) )
1199 nNewX = (dy * md) / mn + lx;
1200 else
1202 BigInt ady = dy;
1203 ady *= md;
1204 if( ady.IsNeg() )
1205 if( mn < 0 )
1206 ady += mn/2;
1207 else
1208 ady -= (mn-1)/2;
1209 else
1210 if( mn < 0 )
1211 ady -= (mn+1)/2;
1212 else
1213 ady += mn/2;
1214 ady /= mn;
1215 nNewX = (long)ady + lx;
1218 else
1220 nNewX = (nEdge == EDGE_LEFT) ? mnLow : mnHigh;
1221 long dx = nNewX - lx;
1222 if ( !mn )
1223 nNewY = ly;
1224 else if ( (LONG_MAX / std::abs(mn)) >= std::abs(dx) )
1225 nNewY = (dx * mn) / md + ly;
1226 else
1228 BigInt adx = dx;
1229 adx *= mn;
1230 if( adx.IsNeg() )
1231 if( md < 0 )
1232 adx += md/2;
1233 else
1234 adx -= (md-1)/2;
1235 else
1236 if( md < 0 )
1237 adx -= (md+1)/2;
1238 else
1239 adx += md/2;
1240 adx /= md;
1241 nNewY = (long)adx + ly;
1245 return Point( nNewX, nNewY );
1248 void ImplEdgePointFilter::Input( const Point& rPoint )
1250 int nOutside = VisibleSide( rPoint );
1252 if ( mbFirst )
1254 maFirstPoint = rPoint;
1255 mbFirst = false;
1256 if ( !nOutside )
1257 mrNextFilter.Input( rPoint );
1259 else if ( rPoint == maLastPoint )
1260 return;
1261 else if ( !nOutside )
1263 if ( mnLastOutside )
1264 mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1265 mrNextFilter.Input( rPoint );
1267 else if ( !mnLastOutside )
1268 mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1269 else if ( nOutside != mnLastOutside )
1271 mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1272 mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1275 maLastPoint = rPoint;
1276 mnLastOutside = nOutside;
1279 void ImplEdgePointFilter::LastPoint()
1281 if ( !mbFirst )
1283 int nOutside = VisibleSide( maFirstPoint );
1285 if ( nOutside != mnLastOutside )
1286 Input( maFirstPoint );
1287 mrNextFilter.LastPoint();
1291 void Polygon::Clip( const Rectangle& rRect, bool bPolygon )
1293 // #105251# Justify rect before edge filtering
1294 Rectangle aJustifiedRect( rRect );
1295 aJustifiedRect.Justify();
1297 sal_uInt16 nSourceSize = mpImplPolygon->mnPoints;
1298 ImplPolygonPointFilter aPolygon( nSourceSize );
1299 ImplEdgePointFilter aHorzFilter( EDGE_HORZ, aJustifiedRect.Left(), aJustifiedRect.Right(),
1300 aPolygon );
1301 ImplEdgePointFilter aVertFilter( EDGE_VERT, aJustifiedRect.Top(), aJustifiedRect.Bottom(),
1302 aHorzFilter );
1304 for ( sal_uInt16 i = 0; i < nSourceSize; i++ )
1305 aVertFilter.Input( mpImplPolygon->mpPointAry[i] );
1306 if ( bPolygon || aVertFilter.IsPolygon() )
1307 aVertFilter.LastPoint();
1308 else
1309 aPolygon.LastPoint();
1311 // Delete old ImpPolygon-data and assign from ImpPolygonPointFilter
1312 if ( mpImplPolygon->mnRefCount )
1314 if ( mpImplPolygon->mnRefCount > 1 )
1315 mpImplPolygon->mnRefCount--;
1316 else
1317 delete mpImplPolygon;
1319 mpImplPolygon = aPolygon.release();
1322 Rectangle Polygon::GetBoundRect() const
1324 // Removing the assert. Bezier curves have the attribute that each single
1325 // curve segment defined by four points can not exit the four-point polygon
1326 // defined by that points. This allows to say that the curve segment can also
1327 // never leave the Range of it's defining points.
1328 // The result is that Polygon::GetBoundRect() may not create the minimal
1329 // BoundRect of the Polygon (to get that, use basegfx::B2DPolygon classes),
1330 // but will always create a valid BoundRect, at least as long as this method
1331 // 'blindly' travels over all points, including control points.
1333 // DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetBoundRect could fail with beziers!" );
1335 sal_uInt16 nCount = mpImplPolygon->mnPoints;
1336 if( ! nCount )
1337 return Rectangle();
1339 long nXMin, nXMax, nYMin, nYMax;
1341 const Point* pPt = &(mpImplPolygon->mpPointAry[0]);
1342 nXMin = nXMax = pPt->X();
1343 nYMin = nYMax = pPt->Y();
1345 for ( sal_uInt16 i = 0; i < nCount; i++ )
1347 pPt = &(mpImplPolygon->mpPointAry[i]);
1349 if ( pPt->X() < nXMin )
1350 nXMin = pPt->X();
1351 if ( pPt->X() > nXMax )
1352 nXMax = pPt->X();
1353 if ( pPt->Y() < nYMin )
1354 nYMin = pPt->Y();
1355 if ( pPt->Y() > nYMax )
1356 nYMax = pPt->Y();
1359 return Rectangle( nXMin, nYMin, nXMax, nYMax );
1362 double Polygon::GetSignedArea() const
1364 DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetArea could fail with beziers!" );
1366 double fArea = 0.0;
1368 if( mpImplPolygon->mnPoints > 2 )
1370 const sal_uInt16 nCount1 = mpImplPolygon->mnPoints - 1;
1372 for( sal_uInt16 i = 0; i < nCount1; )
1374 const Point& rPt = mpImplPolygon->mpPointAry[ i ];
1375 const Point& rPt1 = mpImplPolygon->mpPointAry[ ++i ];
1376 fArea += ( rPt.X() - rPt1.X() ) * ( rPt.Y() + rPt1.Y() );
1379 const Point& rPt = mpImplPolygon->mpPointAry[ nCount1 ];
1380 const Point& rPt0 = mpImplPolygon->mpPointAry[ 0 ];
1381 fArea += ( rPt.X() - rPt0.X() ) * ( rPt.Y() + rPt0.Y() );
1384 return fArea;
1387 bool Polygon::IsInside( const Point& rPoint ) const
1389 DBG_ASSERT( !mpImplPolygon->mpFlagAry, "IsInside could fail with beziers!" );
1391 const Rectangle aBound( GetBoundRect() );
1392 const Line aLine( rPoint, Point( aBound.Right() + 100L, rPoint.Y() ) );
1393 sal_uInt16 nCount = mpImplPolygon->mnPoints;
1394 sal_uInt16 nPCounter = 0;
1396 if ( ( nCount > 2 ) && aBound.IsInside( rPoint ) )
1398 Point aPt1( mpImplPolygon->mpPointAry[ 0 ] );
1399 Point aIntersection;
1400 Point aLastIntersection;
1402 while ( ( aPt1 == mpImplPolygon->mpPointAry[ nCount - 1 ] ) && ( nCount > 3 ) )
1403 nCount--;
1405 for ( sal_uInt16 i = 1; i <= nCount; i++ )
1407 const Point& rPt2 = mpImplPolygon->mpPointAry[ ( i < nCount ) ? i : 0 ];
1409 if ( aLine.Intersection( Line( aPt1, rPt2 ), aIntersection ) )
1411 // This avoids insertion of double intersections
1412 if ( nPCounter )
1414 if ( aIntersection != aLastIntersection )
1416 aLastIntersection = aIntersection;
1417 nPCounter++;
1420 else
1422 aLastIntersection = aIntersection;
1423 nPCounter++;
1427 aPt1 = rPt2;
1431 // is inside, if number of intersection points is odd
1432 return ( ( nPCounter & 1 ) == 1 );
1435 bool Polygon::IsRightOrientated() const
1437 return GetSignedArea() >= 0.0;
1440 void Polygon::Insert( sal_uInt16 nPos, const Point& rPt, PolyFlags eFlags )
1442 ImplMakeUnique();
1444 if( nPos >= mpImplPolygon->mnPoints )
1445 nPos = mpImplPolygon->mnPoints;
1447 mpImplPolygon->ImplSplit( nPos, 1 );
1448 mpImplPolygon->mpPointAry[ nPos ] = rPt;
1450 if( POLY_NORMAL != eFlags )
1452 mpImplPolygon->ImplCreateFlagArray();
1453 mpImplPolygon->mpFlagAry[ nPos ] = (sal_uInt8) eFlags;
1457 void Polygon::Insert( sal_uInt16 nPos, const Polygon& rPoly )
1459 const sal_uInt16 nInsertCount = rPoly.mpImplPolygon->mnPoints;
1461 if( nInsertCount )
1463 ImplMakeUnique();
1465 if( nPos >= mpImplPolygon->mnPoints )
1466 nPos = mpImplPolygon->mnPoints;
1468 if( rPoly.mpImplPolygon->mpFlagAry )
1469 mpImplPolygon->ImplCreateFlagArray();
1471 mpImplPolygon->ImplSplit( nPos, nInsertCount, rPoly.mpImplPolygon );
1475 Point& Polygon::operator[]( sal_uInt16 nPos )
1477 DBG_ASSERT( nPos < mpImplPolygon->mnPoints, "Polygon::[]: nPos >= nPoints" );
1479 ImplMakeUnique();
1480 return mpImplPolygon->mpPointAry[nPos];
1483 Polygon& Polygon::operator=( const Polygon& rPoly )
1485 DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
1487 // Increase refcounter before assigning
1488 // Note: RefCount == 0 for static objects
1489 if ( rPoly.mpImplPolygon->mnRefCount )
1490 rPoly.mpImplPolygon->mnRefCount++;
1492 // Delete if recount == 0, otherwise decrement
1493 if ( mpImplPolygon->mnRefCount )
1495 if ( mpImplPolygon->mnRefCount > 1 )
1496 mpImplPolygon->mnRefCount--;
1497 else
1498 delete mpImplPolygon;
1501 mpImplPolygon = rPoly.mpImplPolygon;
1502 return *this;
1505 bool Polygon::operator==( const Polygon& rPoly ) const
1508 if ( (rPoly.mpImplPolygon == mpImplPolygon) )
1509 return true;
1510 else
1511 return false;
1514 bool Polygon::IsEqual( const Polygon& rPoly ) const
1516 bool bIsEqual = true;
1517 sal_uInt16 i;
1518 if ( GetSize() != rPoly.GetSize() )
1519 bIsEqual = false;
1520 else
1522 for ( i = 0; i < GetSize(); i++ )
1524 if ( ( GetPoint( i ) != rPoly.GetPoint( i ) ) ||
1525 ( GetFlags( i ) != rPoly.GetFlags( i ) ) )
1527 bIsEqual = false;
1528 break;
1532 return bIsEqual;
1535 SvStream& ReadPolygon( SvStream& rIStream, Polygon& rPoly )
1537 DBG_ASSERTWARNING( rIStream.GetVersion(), "Polygon::>> - Solar-Version not set on rIStream" );
1539 sal_uInt16 i;
1540 sal_uInt16 nPoints(0);
1542 // read all points and create array
1543 rIStream.ReadUInt16( nPoints );
1545 const size_t nMaxRecordsPossible = rIStream.remainingSize() / (2 * sizeof(sal_Int32));
1546 if (nPoints > nMaxRecordsPossible)
1548 SAL_WARN("tools", "Polygon claims " << nPoints << " records, but only " << nMaxRecordsPossible << " possible");
1549 nPoints = nMaxRecordsPossible;
1552 if ( rPoly.mpImplPolygon->mnRefCount != 1 )
1554 if ( rPoly.mpImplPolygon->mnRefCount )
1555 rPoly.mpImplPolygon->mnRefCount--;
1556 rPoly.mpImplPolygon = new ImplPolygon( nPoints );
1558 else
1559 rPoly.mpImplPolygon->ImplSetSize( nPoints, false );
1562 // Determine whether we need to write through operators
1563 #if (SAL_TYPES_SIZEOFLONG) == 4
1564 #ifdef OSL_BIGENDIAN
1565 if ( rIStream.GetEndian() == SvStreamEndian::BIG )
1566 #else
1567 if ( rIStream.GetEndian() == SvStreamEndian::LITTLE )
1568 #endif
1569 rIStream.Read( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
1570 else
1571 #endif
1573 for( i = 0; i < nPoints; i++ )
1575 sal_Int32 nTmpX(0), nTmpY(0);
1576 rIStream.ReadInt32( nTmpX ).ReadInt32( nTmpY );
1577 rPoly.mpImplPolygon->mpPointAry[i].X() = nTmpX;
1578 rPoly.mpImplPolygon->mpPointAry[i].Y() = nTmpY;
1583 return rIStream;
1586 SvStream& WritePolygon( SvStream& rOStream, const Polygon& rPoly )
1588 DBG_ASSERTWARNING( rOStream.GetVersion(), "Polygon::<< - Solar-Version not set on rOStream" );
1590 sal_uInt16 i;
1591 sal_uInt16 nPoints = rPoly.GetSize();
1593 // Write number of points
1594 rOStream.WriteUInt16( nPoints );
1597 // Determine whether we need to write through operators
1598 #if (SAL_TYPES_SIZEOFLONG) == 4
1599 #ifdef OSL_BIGENDIAN
1600 if ( rOStream.GetEndian() == SvStreamEndian::BIG )
1601 #else
1602 if ( rOStream.GetEndian() == SvStreamEndian::LITTLE )
1603 #endif
1605 if ( nPoints )
1606 rOStream.Write( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
1608 else
1609 #endif
1611 for( i = 0; i < nPoints; i++ )
1613 rOStream.WriteInt32( rPoly.mpImplPolygon->mpPointAry[i].X() )
1614 .WriteInt32( rPoly.mpImplPolygon->mpPointAry[i].Y() );
1619 return rOStream;
1622 void Polygon::ImplRead( SvStream& rIStream )
1624 sal_uInt8 bHasPolyFlags(0);
1626 ReadPolygon( rIStream, *this );
1627 rIStream.ReadUChar( bHasPolyFlags );
1629 if ( bHasPolyFlags )
1631 mpImplPolygon->mpFlagAry = new sal_uInt8[ mpImplPolygon->mnPoints ];
1632 rIStream.Read( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
1636 void Polygon::Read( SvStream& rIStream )
1638 VersionCompat aCompat( rIStream, StreamMode::READ );
1640 ImplRead( rIStream );
1643 void Polygon::ImplWrite( SvStream& rOStream ) const
1645 bool bHasPolyFlags = mpImplPolygon->mpFlagAry != NULL;
1646 WritePolygon( rOStream, *this );
1647 rOStream.WriteBool(bHasPolyFlags);
1649 if ( bHasPolyFlags )
1650 rOStream.Write( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
1653 void Polygon::Write( SvStream& rOStream ) const
1655 VersionCompat aCompat( rOStream, StreamMode::WRITE, 1 );
1657 ImplWrite( rOStream );
1660 // #i74631#/#i115917# numerical correction method for B2DPolygon
1661 void impCorrectContinuity(basegfx::B2DPolygon& roPolygon, sal_uInt32 nIndex, sal_uInt8 nCFlag)
1663 const sal_uInt32 nPointCount(roPolygon.count());
1664 OSL_ENSURE(nIndex < nPointCount, "impCorrectContinuity: index access out of range (!)");
1666 if(nIndex < nPointCount && (POLY_SMOOTH == nCFlag || POLY_SYMMTR == nCFlag))
1668 if(roPolygon.isPrevControlPointUsed(nIndex) && roPolygon.isNextControlPointUsed(nIndex))
1670 // #i115917# Patch from osnola (modified, thanks for showing the porblem)
1672 // The correction is needed because an integer polygon with control points
1673 // is converted to double precision. When C1 or C2 is used the involved vectors
1674 // may not have the same directions/lengths since these come from integer coordinates
1675 // and may have been snapped to different nearest integer coordinates. The snap error
1676 // is in the range of +-1 in y and y, thus 0.0 <= error <= sqrt(2.0). Nonetheless,
1677 // it needs to be corrected to be able to detect the continuity in this points
1678 // correctly.
1680 // We only have the integer data here (already in double precision form, but no mantisses
1681 // used), so the best correction is to use:
1683 // for C1: The longest vector since it potentially has best preserved the original vector.
1684 // Even better the sum of the vectors, weighted by their length. This gives the
1685 // normal vector addition to get the vector itself, lengths need to be preserved.
1686 // for C2: The mediated vector(s) since both should be the same, but mirrored
1688 // extract the point and vectors
1689 const basegfx::B2DPoint aPoint(roPolygon.getB2DPoint(nIndex));
1690 const basegfx::B2DVector aNext(roPolygon.getNextControlPoint(nIndex) - aPoint);
1691 const basegfx::B2DVector aPrev(aPoint - roPolygon.getPrevControlPoint(nIndex));
1693 // calculate common direction vector, normalize
1694 const basegfx::B2DVector aDirection(aNext + aPrev);
1696 if(POLY_SMOOTH == nCFlag)
1698 // C1: apply common direction vector, preserve individual lengths
1699 const double fInvDirectionLen(1.0 / aDirection.getLength());
1700 roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + (aDirection * (aNext.getLength() * fInvDirectionLen))));
1701 roPolygon.setPrevControlPoint(nIndex, basegfx::B2DPoint(aPoint - (aDirection * (aPrev.getLength() * fInvDirectionLen))));
1703 else // POLY_SYMMTR
1705 // C2: get mediated length. Taking half of the unnormalized direction would be
1706 // an approximation, but not correct.
1707 const double fMedLength((aNext.getLength() + aPrev.getLength()) * (0.5 / aDirection.getLength()));
1708 const basegfx::B2DVector aScaledDirection(aDirection * fMedLength);
1710 // Bring Direction to correct length and apply
1711 roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + aScaledDirection));
1712 roPolygon.setPrevControlPoint(nIndex, basegfx::B2DPoint(aPoint - aScaledDirection));
1718 // convert to basegfx::B2DPolygon and return
1719 basegfx::B2DPolygon Polygon::getB2DPolygon() const
1721 basegfx::B2DPolygon aRetval;
1722 const sal_uInt16 nCount(mpImplPolygon->mnPoints);
1724 if(nCount)
1726 if(mpImplPolygon->mpFlagAry)
1728 // handling for curves. Add start point
1729 const Point aStartPoint(mpImplPolygon->mpPointAry[0]);
1730 sal_uInt8 nPointFlag(mpImplPolygon->mpFlagAry[0]);
1731 aRetval.append(basegfx::B2DPoint(aStartPoint.X(), aStartPoint.Y()));
1732 Point aControlA, aControlB;
1734 for(sal_uInt16 a(1); a < nCount;)
1736 bool bControlA(false);
1737 bool bControlB(false);
1739 if(POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
1741 aControlA = mpImplPolygon->mpPointAry[a++];
1742 bControlA = true;
1745 if(a < nCount && POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
1747 aControlB = mpImplPolygon->mpPointAry[a++];
1748 bControlB = true;
1751 // assert invalid polygons
1752 OSL_ENSURE(bControlA == bControlB, "Polygon::getB2DPolygon: Invalid source polygon (!)");
1753 (void)bControlB;
1755 if(a < nCount)
1757 const Point aEndPoint(mpImplPolygon->mpPointAry[a]);
1759 if(bControlA)
1761 // bezier edge, add
1762 aRetval.appendBezierSegment(
1763 basegfx::B2DPoint(aControlA.X(), aControlA.Y()),
1764 basegfx::B2DPoint(aControlB.X(), aControlB.Y()),
1765 basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
1767 impCorrectContinuity(aRetval, aRetval.count() - 2, nPointFlag);
1769 else
1771 // no bezier edge, add end point
1772 aRetval.append(basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
1775 nPointFlag = mpImplPolygon->mpFlagAry[a++];
1779 // if exist, remove double first/last points, set closed and correct control points
1780 basegfx::tools::checkClosed(aRetval);
1782 if(aRetval.isClosed())
1784 // closeWithGeometryChange did really close, so last point(s) were removed.
1785 // Correct the continuity in the changed point
1786 impCorrectContinuity(aRetval, 0, mpImplPolygon->mpFlagAry[0]);
1789 else
1791 // extra handling for non-curves (most-used case) for speedup
1792 for(sal_uInt16 a(0); a < nCount; a++)
1794 // get point and add
1795 const Point aPoint(mpImplPolygon->mpPointAry[a]);
1796 aRetval.append(basegfx::B2DPoint(aPoint.X(), aPoint.Y()));
1799 // set closed flag
1800 basegfx::tools::checkClosed(aRetval);
1804 return aRetval;
1807 // constructor to convert from basegfx::B2DPolygon
1808 // #i76891# Needed to change from adding all control points (even for unused
1809 // edges) and creating a fixed-size Polygon in the first run to creating the
1810 // minimal Polygon. This requires a temporary Point- and Flag-Array for curves
1811 // and a memcopy at ImplPolygon creation, but contains no zero-controlpoints
1812 // for straight edges.
1813 Polygon::Polygon(const basegfx::B2DPolygon& rPolygon)
1814 : mpImplPolygon(0)
1816 const bool bCurve(rPolygon.areControlPointsUsed());
1817 const bool bClosed(rPolygon.isClosed());
1818 sal_uInt32 nB2DLocalCount(rPolygon.count());
1820 if(bCurve)
1822 // #127979# Reduce source point count hard to the limit of the tools Polygon
1823 if(nB2DLocalCount > ((0x0000ffff / 3L) - 1L))
1825 OSL_FAIL("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
1826 nB2DLocalCount = ((0x0000ffff / 3L) - 1L);
1829 // calculate target point count
1830 const sal_uInt32 nLoopCount(bClosed ? nB2DLocalCount : (nB2DLocalCount ? nB2DLocalCount - 1L : 0L ));
1832 if(nLoopCount)
1834 // calculate maximum array size and allocate; prepare insert index
1835 const sal_uInt32 nMaxTargetCount((nLoopCount * 3) + 1);
1836 mpImplPolygon = new ImplPolygon(static_cast< sal_uInt16 >(nMaxTargetCount), true);
1838 // prepare insert index and current point
1839 sal_uInt32 nArrayInsert(0);
1840 basegfx::B2DCubicBezier aBezier;
1841 aBezier.setStartPoint(rPolygon.getB2DPoint(0));
1843 for(sal_uInt32 a(0L); a < nLoopCount; a++)
1845 // add current point (always) and remember StartPointIndex for evtl. later corrections
1846 const Point aStartPoint(FRound(aBezier.getStartPoint().getX()), FRound(aBezier.getStartPoint().getY()));
1847 const sal_uInt32 nStartPointIndex(nArrayInsert);
1848 mpImplPolygon->mpPointAry[nStartPointIndex] = aStartPoint;
1849 mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_NORMAL;
1850 nArrayInsert++;
1852 // prepare next segment
1853 const sal_uInt32 nNextIndex((a + 1) % nB2DLocalCount);
1854 aBezier.setEndPoint(rPolygon.getB2DPoint(nNextIndex));
1855 aBezier.setControlPointA(rPolygon.getNextControlPoint(a));
1856 aBezier.setControlPointB(rPolygon.getPrevControlPoint(nNextIndex));
1858 if(aBezier.isBezier())
1860 // if one is used, add always two control points due to the old schema
1861 mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointA().getX()), FRound(aBezier.getControlPointA().getY()));
1862 mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
1863 nArrayInsert++;
1865 mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointB().getX()), FRound(aBezier.getControlPointB().getY()));
1866 mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
1867 nArrayInsert++;
1870 // test continuity with previous control point to set flag value
1871 if(aBezier.getControlPointA() != aBezier.getStartPoint() && (bClosed || a))
1873 const basegfx::B2VectorContinuity eCont(rPolygon.getContinuityInPoint(a));
1875 if(basegfx::CONTINUITY_C1 == eCont)
1877 mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SMOOTH;
1879 else if(basegfx::CONTINUITY_C2 == eCont)
1881 mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SYMMTR;
1885 // prepare next polygon step
1886 aBezier.setStartPoint(aBezier.getEndPoint());
1889 if(bClosed)
1891 // add first point again as closing point due to old definition
1892 mpImplPolygon->mpPointAry[nArrayInsert] = mpImplPolygon->mpPointAry[0];
1893 mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
1894 nArrayInsert++;
1896 else
1898 // add last point as closing point
1899 const basegfx::B2DPoint aClosingPoint(rPolygon.getB2DPoint(nB2DLocalCount - 1L));
1900 const Point aEnd(FRound(aClosingPoint.getX()), FRound(aClosingPoint.getY()));
1901 mpImplPolygon->mpPointAry[nArrayInsert] = aEnd;
1902 mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
1903 nArrayInsert++;
1906 DBG_ASSERT(nArrayInsert <= nMaxTargetCount, "Polygon::Polygon from basegfx::B2DPolygon: wrong max point count estimation (!)");
1908 if(nArrayInsert != nMaxTargetCount)
1910 mpImplPolygon->ImplSetSize(static_cast< sal_uInt16 >(nArrayInsert), true);
1914 else
1916 // #127979# Reduce source point count hard to the limit of the tools Polygon
1917 if(nB2DLocalCount > (0x0000ffff - 1L))
1919 OSL_FAIL("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
1920 nB2DLocalCount = (0x0000ffff - 1L);
1923 if(nB2DLocalCount)
1925 // point list creation
1926 const sal_uInt32 nTargetCount(nB2DLocalCount + (bClosed ? 1L : 0L));
1927 mpImplPolygon = new ImplPolygon( static_cast< sal_uInt16 >(nTargetCount) );
1928 sal_uInt16 nIndex(0);
1930 for(sal_uInt32 a(0L); a < nB2DLocalCount; a++)
1932 basegfx::B2DPoint aB2DPoint(rPolygon.getB2DPoint(a));
1933 Point aPoint(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY()));
1934 mpImplPolygon->mpPointAry[nIndex++] = aPoint;
1937 if(bClosed)
1939 // add first point as closing point
1940 mpImplPolygon->mpPointAry[nIndex] = mpImplPolygon->mpPointAry[0];
1945 if(!mpImplPolygon)
1947 // no content yet, create empty polygon
1948 mpImplPolygon = static_cast<ImplPolygon*>(&aStaticImplPolygon);
1952 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */