bump product version to 4.1.6.2
[LibreOffice.git] / tools / source / generic / poly.cxx
blob689f35a8f480e8ab4df7965be8df8a4af496f1cd
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 <tools/bigint.hxx>
22 #include <tools/debug.hxx>
23 #include <tools/helpers.hxx>
24 #include <tools/stream.hxx>
25 #include <tools/vcompat.hxx>
26 #include <tools/gen.hxx>
27 #include <poly.h>
28 #include <tools/line.hxx>
29 #include <tools/vector2d.hxx>
30 #include <tools/poly.hxx>
31 #include <basegfx/polygon/b2dpolygon.hxx>
32 #include <basegfx/point/b2dpoint.hxx>
33 #include <basegfx/vector/b2dvector.hxx>
34 #include <basegfx/polygon/b2dpolygontools.hxx>
35 #include <basegfx/curve/b2dcubicbezier.hxx>
37 #include <vector>
38 #include <iterator>
39 #include <algorithm>
40 #include <cstring>
41 #include <limits.h>
42 #include <cmath>
44 DBG_NAME( Polygon )
46 #define EDGE_LEFT 1
47 #define EDGE_TOP 2
48 #define EDGE_RIGHT 4
49 #define EDGE_BOTTOM 8
50 #define EDGE_HORZ (EDGE_RIGHT | EDGE_LEFT)
51 #define EDGE_VERT (EDGE_TOP | EDGE_BOTTOM)
52 #define SMALL_DVALUE 0.0000001
53 #define FSQRT2 1.4142135623730950488016887242097
55 static ImplPolygonData aStaticImplPolygon =
57 NULL, NULL, 0, 0
60 ImplPolygon::ImplPolygon( sal_uInt16 nInitSize, sal_Bool bFlags )
62 if ( nInitSize )
64 mpPointAry = (Point*)new char[(sal_uIntPtr)nInitSize*sizeof(Point)];
65 memset( mpPointAry, 0, (sal_uIntPtr)nInitSize*sizeof(Point) );
67 else
68 mpPointAry = NULL;
70 if( bFlags )
72 mpFlagAry = new sal_uInt8[ nInitSize ];
73 memset( mpFlagAry, 0, nInitSize );
75 else
76 mpFlagAry = NULL;
78 mnRefCount = 1;
79 mnPoints = nInitSize;
82 ImplPolygon::ImplPolygon( const ImplPolygon& rImpPoly )
84 if ( rImpPoly.mnPoints )
86 mpPointAry = (Point*)new char[(sal_uIntPtr)rImpPoly.mnPoints*sizeof(Point)];
87 memcpy( mpPointAry, rImpPoly.mpPointAry, (sal_uIntPtr)rImpPoly.mnPoints*sizeof(Point) );
89 if( rImpPoly.mpFlagAry )
91 mpFlagAry = new sal_uInt8[ rImpPoly.mnPoints ];
92 memcpy( mpFlagAry, rImpPoly.mpFlagAry, rImpPoly.mnPoints );
94 else
95 mpFlagAry = NULL;
97 else
99 mpPointAry = NULL;
100 mpFlagAry = NULL;
103 mnRefCount = 1;
104 mnPoints = rImpPoly.mnPoints;
107 ImplPolygon::ImplPolygon( sal_uInt16 nInitSize, const Point* pInitAry, const sal_uInt8* pInitFlags )
109 if ( nInitSize )
111 mpPointAry = (Point*)new char[(sal_uIntPtr)nInitSize*sizeof(Point)];
112 memcpy( mpPointAry, pInitAry, (sal_uIntPtr)nInitSize*sizeof( Point ) );
114 if( pInitFlags )
116 mpFlagAry = new sal_uInt8[ nInitSize ];
117 memcpy( mpFlagAry, pInitFlags, nInitSize );
119 else
120 mpFlagAry = NULL;
122 else
124 mpPointAry = NULL;
125 mpFlagAry = NULL;
128 mnRefCount = 1;
129 mnPoints = nInitSize;
132 ImplPolygon::~ImplPolygon()
134 if ( mpPointAry )
136 delete[] (char*) mpPointAry;
139 if( mpFlagAry )
140 delete[] mpFlagAry;
143 void ImplPolygon::ImplSetSize( sal_uInt16 nNewSize, sal_Bool bResize )
145 if( mnPoints == nNewSize )
146 return;
148 Point* pNewAry;
150 if ( nNewSize )
152 pNewAry = (Point*)new char[(sal_uIntPtr)nNewSize*sizeof(Point)];
154 if ( bResize )
156 // Alte Punkte kopieren
157 if ( mnPoints < nNewSize )
159 // Neue Punkte mit 0 initialisieren
160 memset( pNewAry+mnPoints, 0, (sal_uIntPtr)(nNewSize-mnPoints)*sizeof(Point) );
161 if ( mpPointAry )
162 memcpy( pNewAry, mpPointAry, mnPoints*sizeof(Point) );
164 else
166 if ( mpPointAry )
167 memcpy( pNewAry, mpPointAry, (sal_uIntPtr)nNewSize*sizeof(Point) );
171 else
172 pNewAry = NULL;
174 if ( mpPointAry )
175 delete[] (char*) mpPointAry;
177 // ggf. FlagArray beruecksichtigen
178 if( mpFlagAry )
180 sal_uInt8* pNewFlagAry;
182 if( nNewSize )
184 pNewFlagAry = new sal_uInt8[ nNewSize ];
186 if( bResize )
188 // Alte Flags kopieren
189 if ( mnPoints < nNewSize )
191 // Neue Punkte mit 0 initialisieren
192 memset( pNewFlagAry+mnPoints, 0, nNewSize-mnPoints );
193 memcpy( pNewFlagAry, mpFlagAry, mnPoints );
195 else
196 memcpy( pNewFlagAry, mpFlagAry, nNewSize );
199 else
200 pNewFlagAry = NULL;
202 delete[] mpFlagAry;
203 mpFlagAry = pNewFlagAry;
206 mpPointAry = pNewAry;
207 mnPoints = nNewSize;
210 void ImplPolygon::ImplSplit( sal_uInt16 nPos, sal_uInt16 nSpace, ImplPolygon* pInitPoly )
212 const sal_uIntPtr nSpaceSize = nSpace * sizeof( Point );
214 //Can't fit this in :-(, throw ?
215 if (mnPoints + nSpace > USHRT_MAX)
216 return;
218 const sal_uInt16 nNewSize = mnPoints + nSpace;
220 if( nPos >= mnPoints )
222 // Append at the back
223 nPos = mnPoints;
224 ImplSetSize( nNewSize, sal_True );
226 if( pInitPoly )
228 memcpy( mpPointAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
230 if( pInitPoly->mpFlagAry )
231 memcpy( mpFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
234 else
236 const sal_uInt16 nSecPos = nPos + nSpace;
237 const sal_uInt16 nRest = mnPoints - nPos;
239 Point* pNewAry = (Point*) new char[ (sal_uIntPtr) nNewSize * sizeof( Point ) ];
241 memcpy( pNewAry, mpPointAry, nPos * sizeof( Point ) );
243 if( pInitPoly )
244 memcpy( pNewAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
245 else
246 memset( pNewAry + nPos, 0, nSpaceSize );
248 memcpy( pNewAry + nSecPos, mpPointAry + nPos, nRest * sizeof( Point ) );
249 delete[] (char*) mpPointAry;
251 // consider FlagArray
252 if( mpFlagAry )
254 sal_uInt8* pNewFlagAry = new sal_uInt8[ nNewSize ];
256 memcpy( pNewFlagAry, mpFlagAry, nPos );
258 if( pInitPoly && pInitPoly->mpFlagAry )
259 memcpy( pNewFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
260 else
261 memset( pNewFlagAry + nPos, 0, nSpace );
263 memcpy( pNewFlagAry + nSecPos, mpFlagAry + nPos, nRest );
264 delete[] mpFlagAry;
265 mpFlagAry = pNewFlagAry;
268 mpPointAry = pNewAry;
269 mnPoints = nNewSize;
273 void ImplPolygon::ImplCreateFlagArray()
275 if( !mpFlagAry )
277 mpFlagAry = new sal_uInt8[ mnPoints ];
278 memset( mpFlagAry, 0, mnPoints );
282 inline void Polygon::ImplMakeUnique()
284 // copy references if any exist
285 if ( mpImplPolygon->mnRefCount != 1 )
287 if ( mpImplPolygon->mnRefCount )
288 mpImplPolygon->mnRefCount--;
289 mpImplPolygon = new ImplPolygon( *mpImplPolygon );
293 inline double ImplGetParameter( const Point& rCenter, const Point& rPt, double fWR, double fHR )
295 const long nDX = rPt.X() - rCenter.X();
296 double fAngle = atan2( -rPt.Y() + rCenter.Y(), ( ( nDX == 0L ) ? 0.000000001 : nDX ) );
298 return atan2(fWR*sin(fAngle), fHR*cos(fAngle));
301 Polygon::Polygon()
303 DBG_CTOR( Polygon, NULL );
304 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
307 Polygon::Polygon( sal_uInt16 nSize )
309 DBG_CTOR( Polygon, NULL );
311 if ( nSize )
312 mpImplPolygon = new ImplPolygon( nSize );
313 else
314 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
317 Polygon::Polygon( sal_uInt16 nPoints, const Point* pPtAry, const sal_uInt8* pFlagAry )
319 DBG_CTOR( Polygon, NULL );
321 if( nPoints )
322 mpImplPolygon = new ImplPolygon( nPoints, pPtAry, pFlagAry );
323 else
324 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
327 Polygon::Polygon( const Polygon& rPoly )
329 DBG_CTOR( Polygon, NULL );
330 DBG_CHKOBJ( &rPoly, Polygon, NULL );
331 DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
333 mpImplPolygon = rPoly.mpImplPolygon;
334 if ( mpImplPolygon->mnRefCount )
335 mpImplPolygon->mnRefCount++;
338 Polygon::Polygon( const Rectangle& rRect )
340 DBG_CTOR( Polygon, NULL );
342 if ( rRect.IsEmpty() )
343 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
344 else
346 mpImplPolygon = new ImplPolygon( 5 );
347 mpImplPolygon->mpPointAry[0] = rRect.TopLeft();
348 mpImplPolygon->mpPointAry[1] = rRect.TopRight();
349 mpImplPolygon->mpPointAry[2] = rRect.BottomRight();
350 mpImplPolygon->mpPointAry[3] = rRect.BottomLeft();
351 mpImplPolygon->mpPointAry[4] = rRect.TopLeft();
355 Polygon::Polygon( const Rectangle& rRect, sal_uIntPtr nHorzRound, sal_uIntPtr nVertRound )
357 DBG_CTOR( Polygon, NULL );
359 if ( rRect.IsEmpty() )
360 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
361 else
363 Rectangle aRect( rRect );
364 aRect.Justify(); // SJ: i9140
366 nHorzRound = std::min( nHorzRound, (sal_uIntPtr) labs( aRect.GetWidth() >> 1 ) );
367 nVertRound = std::min( nVertRound, (sal_uIntPtr) labs( aRect.GetHeight() >> 1 ) );
369 if( !nHorzRound && !nVertRound )
371 mpImplPolygon = new ImplPolygon( 5 );
372 mpImplPolygon->mpPointAry[0] = aRect.TopLeft();
373 mpImplPolygon->mpPointAry[1] = aRect.TopRight();
374 mpImplPolygon->mpPointAry[2] = aRect.BottomRight();
375 mpImplPolygon->mpPointAry[3] = aRect.BottomLeft();
376 mpImplPolygon->mpPointAry[4] = aRect.TopLeft();
378 else
380 const Point aTL( aRect.Left() + nHorzRound, aRect.Top() + nVertRound );
381 const Point aTR( aRect.Right() - nHorzRound, aRect.Top() + nVertRound );
382 const Point aBR( aRect.Right() - nHorzRound, aRect.Bottom() - nVertRound );
383 const Point aBL( aRect.Left() + nHorzRound, aRect.Bottom() - nVertRound );
384 Polygon* pEllipsePoly = new Polygon( Point(), nHorzRound, nVertRound );
385 sal_uInt16 i, nEnd, nSize4 = pEllipsePoly->GetSize() >> 2;
387 mpImplPolygon = new ImplPolygon( pEllipsePoly->GetSize() + 1 );
389 const Point* pSrcAry = pEllipsePoly->GetConstPointAry();
390 Point* pDstAry = mpImplPolygon->mpPointAry;
392 for( i = 0, nEnd = nSize4; i < nEnd; i++ )
393 ( pDstAry[ i ] = pSrcAry[ i ] ) += aTR;
395 for( nEnd = nEnd + nSize4; i < nEnd; i++ )
396 ( pDstAry[ i ] = pSrcAry[ i ] ) += aTL;
398 for( nEnd = nEnd + nSize4; i < nEnd; i++ )
399 ( pDstAry[ i ] = pSrcAry[ i ] ) += aBL;
401 for( nEnd = nEnd + nSize4; i < nEnd; i++ )
402 ( pDstAry[ i ] = pSrcAry[ i ] ) += aBR;
404 pDstAry[ nEnd ] = pDstAry[ 0 ];
405 delete pEllipsePoly;
410 Polygon::Polygon( const Point& rCenter, long nRadX, long nRadY, sal_uInt16 nPoints )
412 DBG_CTOR( Polygon, NULL );
414 if( nRadX && nRadY )
416 // Compute default (depends on size)
417 if( !nPoints )
419 nPoints = (sal_uInt16) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
420 sqrt( (double) labs( nRadX * nRadY ) ) ) );
422 nPoints = (sal_uInt16) MinMax( nPoints, 32, 256 );
424 if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
425 nPoints >>= 1;
428 // Ceil number of points until divisible by four
429 mpImplPolygon = new ImplPolygon( nPoints = (nPoints + 3) & ~3 );
431 Point* pPt;
432 sal_uInt16 i;
433 sal_uInt16 nPoints2 = nPoints >> 1;
434 sal_uInt16 nPoints4 = nPoints >> 2;
435 double nAngle;
436 double nAngleStep = F_PI2 / ( nPoints4 - 1 );
438 for( i=0, nAngle = 0.0; i < nPoints4; i++, nAngle += nAngleStep )
440 long nX = FRound( nRadX * cos( nAngle ) );
441 long nY = FRound( -nRadY * sin( nAngle ) );
443 pPt = &(mpImplPolygon->mpPointAry[i]);
444 pPt->X() = nX + rCenter.X();
445 pPt->Y() = nY + rCenter.Y();
446 pPt = &(mpImplPolygon->mpPointAry[nPoints2-i-1]);
447 pPt->X() = -nX + rCenter.X();
448 pPt->Y() = nY + rCenter.Y();
449 pPt = &(mpImplPolygon->mpPointAry[i+nPoints2]);
450 pPt->X() = -nX + rCenter.X();
451 pPt->Y() = -nY + rCenter.Y();
452 pPt = &(mpImplPolygon->mpPointAry[nPoints-i-1]);
453 pPt->X() = nX + rCenter.X();
454 pPt->Y() = -nY + rCenter.Y();
457 else
458 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
461 Polygon::Polygon( const Rectangle& rBound, const Point& rStart, const Point& rEnd,
462 PolyStyle eStyle, sal_Bool bFullCircle )
464 DBG_CTOR( Polygon, NULL );
466 const long nWidth = rBound.GetWidth();
467 const long nHeight = rBound.GetHeight();
469 if( ( nWidth > 1 ) && ( nHeight > 1 ) )
471 const Point aCenter( rBound.Center() );
472 const long nRadX = aCenter.X() - rBound.Left();
473 const long nRadY = aCenter.Y() - rBound.Top();
474 sal_uInt16 nPoints;
476 nPoints = (sal_uInt16) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
477 sqrt( (double) labs( nRadX * nRadY ) ) ) );
479 nPoints = (sal_uInt16) MinMax( nPoints, 32, 256 );
481 if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
482 nPoints >>= 1;
484 // compute threshold
485 const double fRadX = nRadX;
486 const double fRadY = nRadY;
487 const double fCenterX = aCenter.X();
488 const double fCenterY = aCenter.Y();
489 double fStart = ImplGetParameter( aCenter, rStart, fRadX, fRadY );
490 double fEnd = ImplGetParameter( aCenter, rEnd, fRadX, fRadY );
491 double fDiff = fEnd - fStart;
492 double fStep;
493 sal_uInt16 nStart;
494 sal_uInt16 nEnd;
496 if( fDiff < 0. )
497 fDiff += F_2PI;
499 if ( bFullCircle )
500 fDiff = F_2PI;
502 // Proportionally shrink number of points( fDiff / (2PI) );
503 nPoints = std::max( (sal_uInt16) ( ( fDiff * 0.1591549 ) * nPoints ), (sal_uInt16) 16 );
504 fStep = fDiff / ( nPoints - 1 );
506 if( POLY_PIE == eStyle )
508 const Point aCenter2( FRound( fCenterX ), FRound( fCenterY ) );
510 nStart = 1;
511 nEnd = nPoints + 1;
512 mpImplPolygon = new ImplPolygon( nPoints + 2 );
513 mpImplPolygon->mpPointAry[ 0 ] = aCenter2;
514 mpImplPolygon->mpPointAry[ nEnd ] = aCenter2;
516 else
518 mpImplPolygon = new ImplPolygon( ( POLY_CHORD == eStyle ) ? ( nPoints + 1 ) : nPoints );
519 nStart = 0;
520 nEnd = nPoints;
523 for(; nStart < nEnd; nStart++, fStart += fStep )
525 Point& rPt = mpImplPolygon->mpPointAry[ nStart ];
527 rPt.X() = FRound( fCenterX + fRadX * cos( fStart ) );
528 rPt.Y() = FRound( fCenterY - fRadY * sin( fStart ) );
531 if( POLY_CHORD == eStyle )
532 mpImplPolygon->mpPointAry[ nPoints ] = mpImplPolygon->mpPointAry[ 0 ];
534 else
535 mpImplPolygon = (ImplPolygon*) &aStaticImplPolygon;
538 Polygon::Polygon( const Point& rBezPt1, const Point& rCtrlPt1,
539 const Point& rBezPt2, const Point& rCtrlPt2,
540 sal_uInt16 nPoints )
542 DBG_CTOR( Polygon, NULL );
544 nPoints = ( 0 == nPoints ) ? 25 : ( ( nPoints < 2 ) ? 2 : nPoints );
546 const double fInc = 1.0 / ( nPoints - 1 );
547 double fK_1 = 0.0, fK1_1 = 1.0;
548 double fK_2, fK_3, fK1_2, fK1_3, fK12, fK21;
549 const double fX0 = rBezPt1.X();
550 const double fY0 = rBezPt1.Y();
551 const double fX1 = 3.0 * rCtrlPt1.X();
552 const double fY1 = 3.0 * rCtrlPt1.Y();
553 const double fX2 = 3.0 * rCtrlPt2.X();
554 const double fY2 = 3.0 * rCtrlPt2.Y();
555 const double fX3 = rBezPt2.X();
556 const double fY3 = rBezPt2.Y();
558 mpImplPolygon = new ImplPolygon( nPoints );
560 for( sal_uInt16 i = 0; i < nPoints; i++, fK_1 += fInc, fK1_1 -= fInc )
562 Point& rPt = mpImplPolygon->mpPointAry[ i ];
564 fK_2 = fK_1, fK_3 = ( fK_2 *= fK_1 ), fK_3 *= fK_1;
565 fK1_2 = fK1_1, fK1_3 = ( fK1_2 *= fK1_1 ), fK1_3 *= fK1_1;
566 fK12 = fK_1 * fK1_2, fK21 = fK_2 * fK1_1;
568 rPt.X() = FRound( fK1_3 * fX0 + fK12 * fX1 + fK21 * fX2 + fK_3 * fX3 );
569 rPt.Y() = FRound( fK1_3 * fY0 + fK12 * fY1 + fK21 * fY2 + fK_3 * fY3 );
573 Polygon::~Polygon()
575 DBG_DTOR( Polygon, NULL );
577 // Remove if refcount == 0, otherwise decrement refcount
578 if ( mpImplPolygon->mnRefCount )
580 if ( mpImplPolygon->mnRefCount > 1 )
581 mpImplPolygon->mnRefCount--;
582 else
583 delete mpImplPolygon;
587 const Point* Polygon::GetConstPointAry() const
589 DBG_CHKTHIS( Polygon, NULL );
590 return (Point*)mpImplPolygon->mpPointAry;
593 const sal_uInt8* Polygon::GetConstFlagAry() const
595 DBG_CHKTHIS( Polygon, NULL );
596 return mpImplPolygon->mpFlagAry;
599 void Polygon::SetPoint( const Point& rPt, sal_uInt16 nPos )
601 DBG_CHKTHIS( Polygon, NULL );
602 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
603 "Polygon::SetPoint(): nPos >= nPoints" );
605 ImplMakeUnique();
606 mpImplPolygon->mpPointAry[nPos] = rPt;
609 void Polygon::SetFlags( sal_uInt16 nPos, PolyFlags eFlags )
611 DBG_CHKTHIS( Polygon, NULL );
612 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
613 "Polygon::SetFlags(): nPos >= nPoints" );
615 // we do only want to create the flag array if there
616 // is at least one flag different to POLY_NORMAL
617 if ( mpImplPolygon || ( eFlags != POLY_NORMAL ) )
619 ImplMakeUnique();
620 mpImplPolygon->ImplCreateFlagArray();
621 mpImplPolygon->mpFlagAry[ nPos ] = (sal_uInt8) eFlags;
625 const Point& Polygon::GetPoint( sal_uInt16 nPos ) const
627 DBG_CHKTHIS( Polygon, NULL );
628 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
629 "Polygon::GetPoint(): nPos >= nPoints" );
631 return mpImplPolygon->mpPointAry[nPos];
634 PolyFlags Polygon::GetFlags( sal_uInt16 nPos ) const
636 DBG_CHKTHIS( Polygon, NULL );
637 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
638 "Polygon::GetFlags(): nPos >= nPoints" );
639 return( mpImplPolygon->mpFlagAry ?
640 (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] :
641 POLY_NORMAL );
644 sal_Bool Polygon::HasFlags() const
646 return mpImplPolygon->mpFlagAry != NULL;
649 sal_Bool Polygon::IsRect() const
651 sal_Bool bIsRect = sal_False;
652 if ( mpImplPolygon->mpFlagAry == NULL )
654 if ( ( ( mpImplPolygon->mnPoints == 5 ) && ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ 4 ] ) ) ||
655 ( mpImplPolygon->mnPoints == 4 ) )
657 if ( ( mpImplPolygon->mpPointAry[ 0 ].X() == mpImplPolygon->mpPointAry[ 3 ].X() ) &&
658 ( mpImplPolygon->mpPointAry[ 0 ].Y() == mpImplPolygon->mpPointAry[ 1 ].Y() ) &&
659 ( mpImplPolygon->mpPointAry[ 1 ].X() == mpImplPolygon->mpPointAry[ 2 ].X() ) &&
660 ( mpImplPolygon->mpPointAry[ 2 ].Y() == mpImplPolygon->mpPointAry[ 3 ].Y() ) )
661 bIsRect = sal_True;
664 return bIsRect;
667 void Polygon::SetSize( sal_uInt16 nNewSize )
669 DBG_CHKTHIS( Polygon, NULL );
671 if( nNewSize != mpImplPolygon->mnPoints )
673 ImplMakeUnique();
674 mpImplPolygon->ImplSetSize( nNewSize );
678 sal_uInt16 Polygon::GetSize() const
680 DBG_CHKTHIS( Polygon, NULL );
682 return mpImplPolygon->mnPoints;
685 void Polygon::Clear()
687 DBG_CHKTHIS( Polygon, NULL );
689 if ( mpImplPolygon->mnRefCount )
691 if ( mpImplPolygon->mnRefCount > 1 )
692 mpImplPolygon->mnRefCount--;
693 else
694 delete mpImplPolygon;
697 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
700 double Polygon::CalcDistance( sal_uInt16 nP1, sal_uInt16 nP2 )
702 DBG_ASSERT( nP1 < mpImplPolygon->mnPoints,
703 "Polygon::CalcDistance(): nPos1 >= nPoints" );
704 DBG_ASSERT( nP2 < mpImplPolygon->mnPoints,
705 "Polygon::CalcDistance(): nPos2 >= nPoints" );
707 const Point& rP1 = mpImplPolygon->mpPointAry[ nP1 ];
708 const Point& rP2 = mpImplPolygon->mpPointAry[ nP2 ];
709 const double fDx = rP2.X() - rP1.X();
710 const double fDy = rP2.Y() - rP1.Y();
712 return sqrt( fDx * fDx + fDy * fDy );
715 void Polygon::Optimize( sal_uIntPtr nOptimizeFlags, const PolyOptimizeData* pData )
717 DBG_CHKTHIS( Polygon, NULL );
718 DBG_ASSERT( !mpImplPolygon->mpFlagAry, "Optimizing could fail with beziers!" );
720 sal_uInt16 nSize = mpImplPolygon->mnPoints;
722 if( nOptimizeFlags && nSize )
724 if( nOptimizeFlags & POLY_OPTIMIZE_EDGES )
726 const Rectangle aBound( GetBoundRect() );
727 const double fArea = ( aBound.GetWidth() + aBound.GetHeight() ) * 0.5;
728 const sal_uInt16 nPercent = pData ? pData->GetPercentValue() : 50;
730 Optimize( POLY_OPTIMIZE_NO_SAME );
731 ImplReduceEdges( *this, fArea, nPercent );
733 else if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE | POLY_OPTIMIZE_NO_SAME ) )
735 Polygon aNewPoly;
736 const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
737 sal_uIntPtr nReduce;
739 if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE ) )
740 nReduce = pData ? pData->GetAbsValue() : 4UL;
741 else
742 nReduce = 0UL;
744 while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
745 nSize--;
747 if( nSize > 1 )
749 sal_uInt16 nLast = 0, nNewCount = 1;
751 aNewPoly.SetSize( nSize );
752 aNewPoly[ 0 ] = rFirst;
754 for( sal_uInt16 i = 1; i < nSize; i++ )
756 if( ( mpImplPolygon->mpPointAry[ i ] != mpImplPolygon->mpPointAry[ nLast ] ) &&
757 ( !nReduce || ( nReduce < (sal_uIntPtr) FRound( CalcDistance( nLast, i ) ) ) ) )
759 aNewPoly[ nNewCount++ ] = mpImplPolygon->mpPointAry[ nLast = i ];
763 if( nNewCount == 1 )
764 aNewPoly.Clear();
765 else
766 aNewPoly.SetSize( nNewCount );
769 *this = aNewPoly;
772 nSize = mpImplPolygon->mnPoints;
774 if( nSize > 1 )
776 if( ( nOptimizeFlags & POLY_OPTIMIZE_CLOSE ) &&
777 ( mpImplPolygon->mpPointAry[ 0 ] != mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
779 SetSize( mpImplPolygon->mnPoints + 1 );
780 mpImplPolygon->mpPointAry[ mpImplPolygon->mnPoints - 1 ] = mpImplPolygon->mpPointAry[ 0 ];
782 else if( ( nOptimizeFlags & POLY_OPTIMIZE_OPEN ) &&
783 ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
785 const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
787 while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
788 nSize--;
790 SetSize( nSize );
797 /** Recursively subdivide cubic bezier curve via deCasteljau.
799 @param rPointIter
800 Output iterator, where the subdivided polylines are written to.
802 @param d
803 Squared difference of curve to a straight line
805 @param P*
806 Exactly four points, interpreted as support and control points of
807 a cubic bezier curve. Must be in device coordinates, since stop
808 criterion is based on the following assumption: the device has a
809 finite resolution, it is thus sufficient to stop subdivision if the
810 curve does not deviate more than one pixel from a straight line.
813 static void ImplAdaptiveSubdivide( ::std::back_insert_iterator< ::std::vector< Point > >& rPointIter,
814 const double old_d2,
815 int recursionDepth,
816 const double d2,
817 const double P1x, const double P1y,
818 const double P2x, const double P2y,
819 const double P3x, const double P3y,
820 const double P4x, const double P4y )
822 // Hard limit on recursion depth, empiric number.
823 enum {maxRecursionDepth=128};
825 // Perform bezier flatness test (lecture notes from R. Schaback,
826 // Mathematics of Computer-Aided Design, Uni Goettingen, 2000)
828 // ||P(t) - L(t)|| <= max ||b_j - b_0 - j/n(b_n - b_0)||
829 // 0<=j<=n
831 // What is calculated here is an upper bound to the distance from
832 // a line through b_0 and b_3 (P1 and P4 in our notation) and the
833 // curve. We can drop 0 and n from the running indices, since the
834 // argument of max becomes zero for those cases.
835 const double fJ1x( P2x - P1x - 1.0/3.0*(P4x - P1x) );
836 const double fJ1y( P2y - P1y - 1.0/3.0*(P4y - P1y) );
837 const double fJ2x( P3x - P1x - 2.0/3.0*(P4x - P1x) );
838 const double fJ2y( P3y - P1y - 2.0/3.0*(P4y - P1y) );
839 const double distance2( ::std::max( fJ1x*fJ1x + fJ1y*fJ1y,
840 fJ2x*fJ2x + fJ2y*fJ2y) );
842 // stop if error measure does not improve anymore. This is a
843 // safety guard against floating point inaccuracies.
844 // stop at recursion level 128. This is a safety guard against
845 // floating point inaccuracies.
846 // stop if distance from line is guaranteed to be bounded by d
847 if( old_d2 > d2 &&
848 recursionDepth < maxRecursionDepth &&
849 distance2 >= d2 )
851 // deCasteljau bezier arc, split at t=0.5
852 // Foley/vanDam, p. 508
853 const double L1x( P1x ), L1y( P1y );
854 const double L2x( (P1x + P2x)*0.5 ), L2y( (P1y + P2y)*0.5 );
855 const double Hx ( (P2x + P3x)*0.5 ), Hy ( (P2y + P3y)*0.5 );
856 const double L3x( (L2x + Hx)*0.5 ), L3y( (L2y + Hy)*0.5 );
857 const double R4x( P4x ), R4y( P4y );
858 const double R3x( (P3x + P4x)*0.5 ), R3y( (P3y + P4y)*0.5 );
859 const double R2x( (Hx + R3x)*0.5 ), R2y( (Hy + R3y)*0.5 );
860 const double R1x( (L3x + R2x)*0.5 ), R1y( (L3y + R2y)*0.5 );
861 const double L4x( R1x ), L4y( R1y );
863 // subdivide further
864 ++recursionDepth;
865 ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, L1x, L1y, L2x, L2y, L3x, L3y, L4x, L4y);
866 ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, R1x, R1y, R2x, R2y, R3x, R3y, R4x, R4y);
868 else
870 // requested resolution reached.
871 // Add end points to output iterator.
872 // order is preserved, since this is so to say depth first traversal.
873 *rPointIter++ = Point( FRound(P1x), FRound(P1y) );
877 void Polygon::AdaptiveSubdivide( Polygon& rResult, const double d ) const
879 if( !mpImplPolygon->mpFlagAry )
881 rResult = *this;
883 else
885 sal_uInt16 i;
886 sal_uInt16 nPts( GetSize() );
887 ::std::vector< Point > aPoints;
888 aPoints.reserve( nPts );
889 ::std::back_insert_iterator< ::std::vector< Point > > aPointIter( aPoints );
891 for(i=0; i<nPts;)
893 if( ( i + 3 ) < nPts )
895 sal_uInt8 P1( mpImplPolygon->mpFlagAry[ i ] );
896 sal_uInt8 P4( mpImplPolygon->mpFlagAry[ i + 3 ] );
898 if( ( POLY_NORMAL == P1 || POLY_SMOOTH == P1 || POLY_SYMMTR == P1 ) &&
899 ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 1 ] ) &&
900 ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 2 ] ) &&
901 ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
903 ImplAdaptiveSubdivide( aPointIter, d*d+1.0, 0, d*d,
904 mpImplPolygon->mpPointAry[ i ].X(), mpImplPolygon->mpPointAry[ i ].Y(),
905 mpImplPolygon->mpPointAry[ i+1 ].X(), mpImplPolygon->mpPointAry[ i+1 ].Y(),
906 mpImplPolygon->mpPointAry[ i+2 ].X(), mpImplPolygon->mpPointAry[ i+2 ].Y(),
907 mpImplPolygon->mpPointAry[ i+3 ].X(), mpImplPolygon->mpPointAry[ i+3 ].Y() );
908 i += 3;
909 continue;
913 *aPointIter++ = mpImplPolygon->mpPointAry[ i++ ];
915 if (aPoints.size() >= SAL_MAX_UINT16)
917 OSL_ENSURE(aPoints.size() < SAL_MAX_UINT16,
918 "Polygon::AdapativeSubdivision created polygon too many points;"
919 " using original polygon instead");
921 // The resulting polygon can not hold all the points
922 // that we have created so far. Stop the subdivision
923 // and return a copy of the unmodified polygon.
924 rResult = *this;
925 return;
929 // fill result polygon
930 rResult = Polygon( (sal_uInt16)aPoints.size() ); // ensure sufficient size for copy
931 ::std::copy(aPoints.begin(), aPoints.end(), rResult.mpImplPolygon->mpPointAry);
935 void Polygon::ImplReduceEdges( Polygon& rPoly, const double& rArea, sal_uInt16 nPercent )
937 const double fBound = 2000.0 * ( 100 - nPercent ) * 0.01;
938 sal_uInt16 nNumNoChange = 0,
939 nNumRuns = 0;
941 while( nNumNoChange < 2 )
943 sal_uInt16 nPntCnt = rPoly.GetSize(), nNewPos = 0;
944 Polygon aNewPoly( nPntCnt );
945 sal_Bool bChangeInThisRun = sal_False;
947 for( sal_uInt16 n = 0; n < nPntCnt; n++ )
949 sal_Bool bDeletePoint = sal_False;
951 if( ( n + nNumRuns ) % 2 )
953 sal_uInt16 nIndPrev = !n ? nPntCnt - 1 : n - 1;
954 sal_uInt16 nIndPrevPrev = !nIndPrev ? nPntCnt - 1 : nIndPrev - 1;
955 sal_uInt16 nIndNext = ( n == nPntCnt-1 ) ? 0 : n + 1;
956 sal_uInt16 nIndNextNext = ( nIndNext == nPntCnt - 1 ) ? 0 : nIndNext + 1;
957 Vector2D aVec1( rPoly[ nIndPrev ] ); aVec1 -= rPoly[ nIndPrevPrev ];
958 Vector2D aVec2( rPoly[ n ] ); aVec2 -= rPoly[ nIndPrev ];
959 Vector2D aVec3( rPoly[ nIndNext ] ); aVec3 -= rPoly[ n ];
960 Vector2D aVec4( rPoly[ nIndNextNext ] ); aVec4 -= rPoly[ nIndNext ];
961 double fDist1 = aVec1.GetLength(), fDist2 = aVec2.GetLength();
962 double fDist3 = aVec3.GetLength(), fDist4 = aVec4.GetLength();
963 double fTurnB = aVec2.Normalize().Scalar( aVec3.Normalize() );
965 if( fabs( fTurnB ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnB ) > ( 1.0 - SMALL_DVALUE ) )
966 bDeletePoint = sal_True;
967 else
969 Vector2D aVecB( rPoly[ nIndNext ] );
970 double fDistB = ( aVecB -= rPoly[ nIndPrev ] ).GetLength();
971 double fLenWithB = fDist2 + fDist3;
972 double fLenFact = ( fDistB != 0.0 ) ? fLenWithB / fDistB : 1.0;
973 double fTurnPrev = aVec1.Normalize().Scalar( aVec2 );
974 double fTurnNext = aVec3.Scalar( aVec4.Normalize() );
975 double fGradPrev, fGradB, fGradNext;
977 if( fabs( fTurnPrev ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnPrev ) > ( 1.0 - SMALL_DVALUE ) )
978 fGradPrev = 0.0;
979 else
980 fGradPrev = acos( fTurnPrev ) / ( aVec1.IsNegative( aVec2 ) ? -F_PI180 : F_PI180 );
982 fGradB = acos( fTurnB ) / ( aVec2.IsNegative( aVec3 ) ? -F_PI180 : F_PI180 );
984 if( fabs( fTurnNext ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnNext ) > ( 1.0 - SMALL_DVALUE ) )
985 fGradNext = 0.0;
986 else
987 fGradNext = acos( fTurnNext ) / ( aVec3.IsNegative( aVec4 ) ? -F_PI180 : F_PI180 );
989 if( ( fGradPrev > 0.0 && fGradB < 0.0 && fGradNext > 0.0 ) ||
990 ( fGradPrev < 0.0 && fGradB > 0.0 && fGradNext < 0.0 ) )
992 if( ( fLenFact < ( FSQRT2 + SMALL_DVALUE ) ) &&
993 ( ( ( fDist1 + fDist4 ) / ( fDist2 + fDist3 ) ) * 2000.0 ) > fBound )
995 bDeletePoint = sal_True;
998 else
1000 double fRelLen = 1.0 - sqrt( fDistB / rArea );
1002 if( fRelLen < 0.0 )
1003 fRelLen = 0.0;
1004 else if( fRelLen > 1.0 )
1005 fRelLen = 1.0;
1007 if( ( (sal_uInt32) ( ( ( fLenFact - 1.0 ) * 1000000.0 ) + 0.5 ) < fBound ) &&
1008 ( fabs( fGradB ) <= ( fRelLen * fBound * 0.01 ) ) )
1010 bDeletePoint = sal_True;
1016 if( !bDeletePoint )
1017 aNewPoly[ nNewPos++ ] = rPoly[ n ];
1018 else
1019 bChangeInThisRun = sal_True;
1022 if( bChangeInThisRun && nNewPos )
1024 aNewPoly.SetSize( nNewPos );
1025 rPoly = aNewPoly;
1026 nNumNoChange = 0;
1028 else
1029 nNumNoChange++;
1031 nNumRuns++;
1035 void Polygon::Move( long nHorzMove, long nVertMove )
1037 DBG_CHKTHIS( Polygon, NULL );
1039 // This check is required for DrawEngine
1040 if ( !nHorzMove && !nVertMove )
1041 return;
1043 ImplMakeUnique();
1045 // Move points
1046 sal_uInt16 nCount = mpImplPolygon->mnPoints;
1047 for ( sal_uInt16 i = 0; i < nCount; i++ )
1049 Point* pPt = &(mpImplPolygon->mpPointAry[i]);
1050 pPt->X() += nHorzMove;
1051 pPt->Y() += nVertMove;
1055 void Polygon::Translate(const Point& rTrans)
1057 DBG_CHKTHIS( Polygon, NULL );
1058 ImplMakeUnique();
1060 for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1061 mpImplPolygon->mpPointAry[ i ] += rTrans;
1064 void Polygon::Scale( double fScaleX, double fScaleY )
1066 DBG_CHKTHIS( Polygon, NULL );
1067 ImplMakeUnique();
1069 for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1071 Point& rPnt = mpImplPolygon->mpPointAry[i];
1072 rPnt.X() = (long) ( fScaleX * rPnt.X() );
1073 rPnt.Y() = (long) ( fScaleY * rPnt.Y() );
1077 void Polygon::Rotate( const Point& rCenter, sal_uInt16 nAngle10 )
1079 DBG_CHKTHIS( Polygon, NULL );
1080 nAngle10 %= 3600;
1082 if( nAngle10 )
1084 const double fAngle = F_PI1800 * nAngle10;
1085 Rotate( rCenter, sin( fAngle ), cos( fAngle ) );
1089 void Polygon::Rotate( const Point& rCenter, double fSin, double fCos )
1091 DBG_CHKTHIS( Polygon, NULL );
1092 ImplMakeUnique();
1094 long nX, nY;
1095 long nCenterX = rCenter.X();
1096 long nCenterY = rCenter.Y();
1098 for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1100 Point& rPt = mpImplPolygon->mpPointAry[ i ];
1102 nX = rPt.X() - nCenterX;
1103 nY = rPt.Y() - nCenterY;
1104 rPt.X() = (long) FRound( fCos * nX + fSin * nY ) + nCenterX;
1105 rPt.Y() = -(long) FRound( fSin * nX - fCos * nY ) + nCenterY;
1109 class ImplPointFilter
1111 public:
1112 virtual void LastPoint() = 0;
1113 virtual void Input( const Point& rPoint ) = 0;
1115 protected:
1116 ~ImplPointFilter() {}
1119 class ImplPolygonPointFilter : public ImplPointFilter
1121 public:
1122 ImplPolygon* mpPoly; // Don't remove, assigned by polygon
1123 sal_uInt16 mnSize;
1125 ImplPolygonPointFilter( sal_uInt16 nDestSize ) :
1126 mnSize( 0 )
1128 mpPoly = new ImplPolygon( nDestSize );
1131 virtual ~ImplPolygonPointFilter() {}
1133 virtual void LastPoint();
1134 virtual void Input( const Point& rPoint );
1137 void ImplPolygonPointFilter::Input( const Point& rPoint )
1139 if ( !mnSize || (rPoint != mpPoly->mpPointAry[mnSize-1]) )
1141 mnSize++;
1142 if ( mnSize > mpPoly->mnPoints )
1143 mpPoly->ImplSetSize( mnSize );
1144 mpPoly->mpPointAry[mnSize-1] = rPoint;
1148 void ImplPolygonPointFilter::LastPoint()
1150 if ( mnSize < mpPoly->mnPoints )
1151 mpPoly->ImplSetSize( mnSize );
1154 class ImplEdgePointFilter : public ImplPointFilter
1156 Point maFirstPoint;
1157 Point maLastPoint;
1158 ImplPointFilter& mrNextFilter;
1159 const long mnLow;
1160 const long mnHigh;
1161 const int mnEdge;
1162 int mnLastOutside;
1163 sal_Bool mbFirst;
1165 public:
1166 ImplEdgePointFilter( int nEdge, long nLow, long nHigh,
1167 ImplPointFilter& rNextFilter ) :
1168 mrNextFilter( rNextFilter ),
1169 mnLow( nLow ),
1170 mnHigh( nHigh ),
1171 mnEdge( nEdge ),
1172 mbFirst( sal_True )
1176 virtual ~ImplEdgePointFilter() {}
1178 Point EdgeSection( const Point& rPoint, int nEdge ) const;
1179 int VisibleSide( const Point& rPoint ) const;
1180 int IsPolygon() const
1181 { return maFirstPoint == maLastPoint; }
1183 virtual void Input( const Point& rPoint );
1184 virtual void LastPoint();
1187 inline int ImplEdgePointFilter::VisibleSide( const Point& rPoint ) const
1189 if ( mnEdge & EDGE_HORZ )
1191 return rPoint.X() < mnLow ? EDGE_LEFT :
1192 rPoint.X() > mnHigh ? EDGE_RIGHT : 0;
1194 else
1196 return rPoint.Y() < mnLow ? EDGE_TOP :
1197 rPoint.Y() > mnHigh ? EDGE_BOTTOM : 0;
1201 Point ImplEdgePointFilter::EdgeSection( const Point& rPoint, int nEdge ) const
1203 long lx = maLastPoint.X();
1204 long ly = maLastPoint.Y();
1205 long md = rPoint.X() - lx;
1206 long mn = rPoint.Y() - ly;
1207 long nNewX;
1208 long nNewY;
1210 if ( nEdge & EDGE_VERT )
1212 nNewY = (nEdge == EDGE_TOP) ? mnLow : mnHigh;
1213 long dy = nNewY - ly;
1214 if ( !md )
1215 nNewX = lx;
1216 else if ( (LONG_MAX / std::abs(md)) >= std::abs(dy) )
1217 nNewX = (dy * md) / mn + lx;
1218 else
1220 BigInt ady = dy;
1221 ady *= md;
1222 if( ady.IsNeg() )
1223 if( mn < 0 )
1224 ady += mn/2;
1225 else
1226 ady -= (mn-1)/2;
1227 else
1228 if( mn < 0 )
1229 ady -= (mn+1)/2;
1230 else
1231 ady += mn/2;
1232 ady /= mn;
1233 nNewX = (long)ady + lx;
1236 else
1238 nNewX = (nEdge == EDGE_LEFT) ? mnLow : mnHigh;
1239 long dx = nNewX - lx;
1240 if ( !mn )
1241 nNewY = ly;
1242 else if ( (LONG_MAX / std::abs(mn)) >= std::abs(dx) )
1243 nNewY = (dx * mn) / md + ly;
1244 else
1246 BigInt adx = dx;
1247 adx *= mn;
1248 if( adx.IsNeg() )
1249 if( md < 0 )
1250 adx += md/2;
1251 else
1252 adx -= (md-1)/2;
1253 else
1254 if( md < 0 )
1255 adx -= (md+1)/2;
1256 else
1257 adx += md/2;
1258 adx /= md;
1259 nNewY = (long)adx + ly;
1263 return Point( nNewX, nNewY );
1266 void ImplEdgePointFilter::Input( const Point& rPoint )
1268 int nOutside = VisibleSide( rPoint );
1270 if ( mbFirst )
1272 maFirstPoint = rPoint;
1273 mbFirst = sal_False;
1274 if ( !nOutside )
1275 mrNextFilter.Input( rPoint );
1277 else if ( rPoint == maLastPoint )
1278 return;
1279 else if ( !nOutside )
1281 if ( mnLastOutside )
1282 mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1283 mrNextFilter.Input( rPoint );
1285 else if ( !mnLastOutside )
1286 mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1287 else if ( nOutside != mnLastOutside )
1289 mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1290 mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1293 maLastPoint = rPoint;
1294 mnLastOutside = nOutside;
1297 void ImplEdgePointFilter::LastPoint()
1299 if ( !mbFirst )
1301 int nOutside = VisibleSide( maFirstPoint );
1303 if ( nOutside != mnLastOutside )
1304 Input( maFirstPoint );
1305 mrNextFilter.LastPoint();
1309 void Polygon::Clip( const Rectangle& rRect, sal_Bool bPolygon )
1311 // #105251# Justify rect befor edge filtering
1312 Rectangle aJustifiedRect( rRect );
1313 aJustifiedRect.Justify();
1315 sal_uInt16 nSourceSize = mpImplPolygon->mnPoints;
1316 ImplPolygonPointFilter aPolygon( nSourceSize );
1317 ImplEdgePointFilter aHorzFilter( EDGE_HORZ, aJustifiedRect.Left(), aJustifiedRect.Right(),
1318 aPolygon );
1319 ImplEdgePointFilter aVertFilter( EDGE_VERT, aJustifiedRect.Top(), aJustifiedRect.Bottom(),
1320 aHorzFilter );
1322 for ( sal_uInt16 i = 0; i < nSourceSize; i++ )
1323 aVertFilter.Input( mpImplPolygon->mpPointAry[i] );
1324 if ( bPolygon || aVertFilter.IsPolygon() )
1325 aVertFilter.LastPoint();
1326 else
1327 aPolygon.LastPoint();
1329 // Delete old ImpPolygon-data and assign from ImpPolygonPointFilter
1330 if ( mpImplPolygon->mnRefCount )
1332 if ( mpImplPolygon->mnRefCount > 1 )
1333 mpImplPolygon->mnRefCount--;
1334 else
1335 delete mpImplPolygon;
1337 mpImplPolygon = aPolygon.mpPoly;
1340 Rectangle Polygon::GetBoundRect() const
1342 DBG_CHKTHIS( Polygon, NULL );
1343 // Removing the assert. Bezier curves have the attribute that each single
1344 // curve segment defined by four points can not exit the four-point polygon
1345 // defined by that points. This allows to say that the curve segment can also
1346 // never leave the Range of it's defining points.
1347 // The result is that Polygon::GetBoundRect() may not create the minimal
1348 // BoundRect of the Polygon (to get that, use basegfx::B2DPolygon classes),
1349 // but will always create a valid BoundRect, at least as long as this method
1350 // 'blindly' travels over all points, including control points.
1352 // DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetBoundRect could fail with beziers!" );
1354 sal_uInt16 nCount = mpImplPolygon->mnPoints;
1355 if( ! nCount )
1356 return Rectangle();
1358 long nXMin, nXMax, nYMin, nYMax;
1360 const Point* pPt = &(mpImplPolygon->mpPointAry[0]);
1361 nXMin = nXMax = pPt->X();
1362 nYMin = nYMax = pPt->Y();
1364 for ( sal_uInt16 i = 0; i < nCount; i++ )
1366 pPt = &(mpImplPolygon->mpPointAry[i]);
1368 if ( pPt->X() < nXMin )
1369 nXMin = pPt->X();
1370 if ( pPt->X() > nXMax )
1371 nXMax = pPt->X();
1372 if ( pPt->Y() < nYMin )
1373 nYMin = pPt->Y();
1374 if ( pPt->Y() > nYMax )
1375 nYMax = pPt->Y();
1378 return Rectangle( nXMin, nYMin, nXMax, nYMax );
1381 double Polygon::GetSignedArea() const
1383 DBG_CHKTHIS( Polygon, NULL );
1384 DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetArea could fail with beziers!" );
1386 double fArea = 0.0;
1388 if( mpImplPolygon->mnPoints > 2 )
1390 const sal_uInt16 nCount1 = mpImplPolygon->mnPoints - 1;
1392 for( sal_uInt16 i = 0; i < nCount1; )
1394 const Point& rPt = mpImplPolygon->mpPointAry[ i ];
1395 const Point& rPt1 = mpImplPolygon->mpPointAry[ ++i ];
1396 fArea += ( rPt.X() - rPt1.X() ) * ( rPt.Y() + rPt1.Y() );
1399 const Point& rPt = mpImplPolygon->mpPointAry[ nCount1 ];
1400 const Point& rPt0 = mpImplPolygon->mpPointAry[ 0 ];
1401 fArea += ( rPt.X() - rPt0.X() ) * ( rPt.Y() + rPt0.Y() );
1404 return fArea;
1407 sal_Bool Polygon::IsInside( const Point& rPoint ) const
1409 DBG_CHKTHIS( Polygon, NULL );
1410 DBG_ASSERT( !mpImplPolygon->mpFlagAry, "IsInside could fail with beziers!" );
1412 const Rectangle aBound( GetBoundRect() );
1413 const Line aLine( rPoint, Point( aBound.Right() + 100L, rPoint.Y() ) );
1414 sal_uInt16 nCount = mpImplPolygon->mnPoints;
1415 sal_uInt16 nPCounter = 0;
1417 if ( ( nCount > 2 ) && aBound.IsInside( rPoint ) )
1419 Point aPt1( mpImplPolygon->mpPointAry[ 0 ] );
1420 Point aIntersection;
1421 Point aLastIntersection;
1423 while ( ( aPt1 == mpImplPolygon->mpPointAry[ nCount - 1 ] ) && ( nCount > 3 ) )
1424 nCount--;
1426 for ( sal_uInt16 i = 1; i <= nCount; i++ )
1428 const Point& rPt2 = mpImplPolygon->mpPointAry[ ( i < nCount ) ? i : 0 ];
1430 if ( aLine.Intersection( Line( aPt1, rPt2 ), aIntersection ) )
1432 // This avoids insertion of double intersections
1433 if ( nPCounter )
1435 if ( aIntersection != aLastIntersection )
1437 aLastIntersection = aIntersection;
1438 nPCounter++;
1441 else
1443 aLastIntersection = aIntersection;
1444 nPCounter++;
1448 aPt1 = rPt2;
1452 // is inside, if number of intersection points is odd
1453 return ( ( nPCounter & 1 ) == 1 );
1456 sal_Bool Polygon::IsRightOrientated() const
1458 DBG_CHKTHIS( Polygon, NULL );
1459 return GetSignedArea() >= 0.0;
1462 void Polygon::Insert( sal_uInt16 nPos, const Point& rPt, PolyFlags eFlags )
1464 DBG_CHKTHIS( Polygon, NULL );
1465 ImplMakeUnique();
1467 if( nPos >= mpImplPolygon->mnPoints )
1468 nPos = mpImplPolygon->mnPoints;
1470 mpImplPolygon->ImplSplit( nPos, 1 );
1471 mpImplPolygon->mpPointAry[ nPos ] = rPt;
1473 if( POLY_NORMAL != eFlags )
1475 mpImplPolygon->ImplCreateFlagArray();
1476 mpImplPolygon->mpFlagAry[ nPos ] = (sal_uInt8) eFlags;
1480 void Polygon::Insert( sal_uInt16 nPos, const Polygon& rPoly )
1482 DBG_CHKTHIS( Polygon, NULL );
1483 const sal_uInt16 nInsertCount = rPoly.mpImplPolygon->mnPoints;
1485 if( nInsertCount )
1487 ImplMakeUnique();
1489 if( nPos >= mpImplPolygon->mnPoints )
1490 nPos = mpImplPolygon->mnPoints;
1492 if( rPoly.mpImplPolygon->mpFlagAry )
1493 mpImplPolygon->ImplCreateFlagArray();
1495 mpImplPolygon->ImplSplit( nPos, nInsertCount, rPoly.mpImplPolygon );
1499 Point& Polygon::operator[]( sal_uInt16 nPos )
1501 DBG_CHKTHIS( Polygon, NULL );
1502 DBG_ASSERT( nPos < mpImplPolygon->mnPoints, "Polygon::[]: nPos >= nPoints" );
1504 ImplMakeUnique();
1505 return mpImplPolygon->mpPointAry[nPos];
1508 Polygon& Polygon::operator=( const Polygon& rPoly )
1510 DBG_CHKTHIS( Polygon, NULL );
1511 DBG_CHKOBJ( &rPoly, Polygon, NULL );
1512 DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
1514 // Increase refcounter before assigning
1515 // Note: RefCount == 0 for static objects
1516 if ( rPoly.mpImplPolygon->mnRefCount )
1517 rPoly.mpImplPolygon->mnRefCount++;
1519 // Delete if recount == 0, otherwise decrement
1520 if ( mpImplPolygon->mnRefCount )
1522 if ( mpImplPolygon->mnRefCount > 1 )
1523 mpImplPolygon->mnRefCount--;
1524 else
1525 delete mpImplPolygon;
1528 mpImplPolygon = rPoly.mpImplPolygon;
1529 return *this;
1532 sal_Bool Polygon::operator==( const Polygon& rPoly ) const
1534 DBG_CHKTHIS( Polygon, NULL );
1535 DBG_CHKOBJ( &rPoly, Polygon, NULL );
1537 if ( (rPoly.mpImplPolygon == mpImplPolygon) )
1538 return sal_True;
1539 else
1540 return sal_False;
1543 sal_Bool Polygon::IsEqual( const Polygon& rPoly ) const
1545 sal_Bool bIsEqual = sal_True;
1546 sal_uInt16 i;
1547 if ( GetSize() != rPoly.GetSize() )
1548 bIsEqual = sal_False;
1549 else
1551 for ( i = 0; i < GetSize(); i++ )
1553 if ( ( GetPoint( i ) != rPoly.GetPoint( i ) ) ||
1554 ( GetFlags( i ) != rPoly.GetFlags( i ) ) )
1556 bIsEqual = sal_False;
1557 break;
1561 return bIsEqual;
1564 SvStream& operator>>( SvStream& rIStream, Polygon& rPoly )
1566 DBG_CHKOBJ( &rPoly, Polygon, NULL );
1567 DBG_ASSERTWARNING( rIStream.GetVersion(), "Polygon::>> - Solar-Version not set on rIStream" );
1569 sal_uInt16 i;
1570 sal_uInt16 nPoints(0);
1572 // read all points and create array
1573 rIStream >> nPoints;
1574 if ( rPoly.mpImplPolygon->mnRefCount != 1 )
1576 if ( rPoly.mpImplPolygon->mnRefCount )
1577 rPoly.mpImplPolygon->mnRefCount--;
1578 rPoly.mpImplPolygon = new ImplPolygon( nPoints );
1580 else
1581 rPoly.mpImplPolygon->ImplSetSize( nPoints, sal_False );
1584 // Determine whether we need to write through operators
1585 #if (SAL_TYPES_SIZEOFLONG) != 4
1586 if ( 1 )
1587 #else
1588 #ifdef OSL_BIGENDIAN
1589 if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
1590 #else
1591 if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
1592 #endif
1593 #endif
1595 for( i = 0; i < nPoints; i++ )
1597 //fdo#39428 SvStream no longer supports operator>>(long&)
1598 sal_Int32 nTmpX(0), nTmpY(0);
1599 rIStream >> nTmpX >> nTmpY;
1600 rPoly.mpImplPolygon->mpPointAry[i].X() = nTmpX;
1601 rPoly.mpImplPolygon->mpPointAry[i].Y() = nTmpY;
1604 else
1605 rIStream.Read( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
1608 return rIStream;
1611 SvStream& operator<<( SvStream& rOStream, const Polygon& rPoly )
1613 DBG_CHKOBJ( &rPoly, Polygon, NULL );
1614 DBG_ASSERTWARNING( rOStream.GetVersion(), "Polygon::<< - Solar-Version not set on rOStream" );
1616 sal_uInt16 i;
1617 sal_uInt16 nPoints = rPoly.GetSize();
1619 // Write number of points
1620 rOStream << nPoints;
1623 // Determine whether we need to write through operators
1624 #if (SAL_TYPES_SIZEOFLONG) != 4
1625 if ( 1 )
1626 #else
1627 #ifdef OSL_BIGENDIAN
1628 if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
1629 #else
1630 if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
1631 #endif
1632 #endif
1634 for( i = 0; i < nPoints; i++ )
1636 //fdo#39428 SvStream no longer supports operator<<(long)
1637 rOStream << sal::static_int_cast<sal_Int32>( rPoly.mpImplPolygon->mpPointAry[i].X() )
1638 << sal::static_int_cast<sal_Int32>( rPoly.mpImplPolygon->mpPointAry[i].Y() );
1641 else
1643 if ( nPoints )
1644 rOStream.Write( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
1648 return rOStream;
1651 void Polygon::ImplRead( SvStream& rIStream )
1653 sal_uInt8 bHasPolyFlags(0);
1655 rIStream >> *this
1656 >> bHasPolyFlags;
1658 if ( bHasPolyFlags )
1660 mpImplPolygon->mpFlagAry = new sal_uInt8[ mpImplPolygon->mnPoints ];
1661 rIStream.Read( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
1665 void Polygon::Read( SvStream& rIStream )
1667 VersionCompat aCompat( rIStream, STREAM_READ );
1669 ImplRead( rIStream );
1672 void Polygon::ImplWrite( SvStream& rOStream ) const
1674 sal_uInt8 bHasPolyFlags = mpImplPolygon->mpFlagAry != NULL;
1675 rOStream << *this
1676 << bHasPolyFlags;
1678 if ( bHasPolyFlags )
1679 rOStream.Write( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
1682 void Polygon::Write( SvStream& rOStream ) const
1684 VersionCompat aCompat( rOStream, STREAM_WRITE, 1 );
1686 ImplWrite( rOStream );
1689 // #i74631#/#i115917# numerical correction method for B2DPolygon
1690 void impCorrectContinuity(basegfx::B2DPolygon& roPolygon, sal_uInt32 nIndex, sal_uInt8 nCFlag)
1692 const sal_uInt32 nPointCount(roPolygon.count());
1693 OSL_ENSURE(nIndex < nPointCount, "impCorrectContinuity: index access out of range (!)");
1695 if(nIndex < nPointCount && (POLY_SMOOTH == nCFlag || POLY_SYMMTR == nCFlag))
1697 if(roPolygon.isPrevControlPointUsed(nIndex) && roPolygon.isNextControlPointUsed(nIndex))
1699 // #i115917# Patch from osnola (modified, thanks for showing the porblem)
1701 // The correction is needed because an integer polygon with control points
1702 // is converted to double precision. When C1 or C2 is used the involved vectors
1703 // may not have the same directions/lengths since these come from integer coordinates
1704 // and may have been snapped to different nearest integer coordinates. The snap error
1705 // is in the range of +-1 in y and y, thus 0.0 <= error <= sqrt(2.0). Nonetheless,
1706 // it needs to be corrected to be able to detect the continuity in this points
1707 // correctly.
1709 // We only have the integer data here (already in double precision form, but no mantisses
1710 // used), so the best correction is to use:
1712 // for C1: The longest vector since it potentially has best preserved the original vector.
1713 // Even better the sum of the vectors, weighted by their length. This gives the
1714 // normal vector addition to get the vector itself, lengths need to be preserved.
1715 // for C2: The mediated vector(s) since both should be the same, but mirrored
1717 // extract the point and vectors
1718 const basegfx::B2DPoint aPoint(roPolygon.getB2DPoint(nIndex));
1719 const basegfx::B2DVector aNext(roPolygon.getNextControlPoint(nIndex) - aPoint);
1720 const basegfx::B2DVector aPrev(aPoint - roPolygon.getPrevControlPoint(nIndex));
1722 // calculate common direction vector, normalize
1723 const basegfx::B2DVector aDirection(aNext + aPrev);
1725 if(POLY_SMOOTH == nCFlag)
1727 // C1: apply common direction vector, preserve individual lengths
1728 const double fInvDirectionLen(1.0 / aDirection.getLength());
1729 roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + (aDirection * (aNext.getLength() * fInvDirectionLen))));
1730 roPolygon.setPrevControlPoint(nIndex, basegfx::B2DPoint(aPoint - (aDirection * (aPrev.getLength() * fInvDirectionLen))));
1732 else // POLY_SYMMTR
1734 // C2: get mediated length. Taking half of the unnormalized direction would be
1735 // an approximation, but not correct.
1736 const double fMedLength((aNext.getLength() + aPrev.getLength()) * (0.5 / aDirection.getLength()));
1737 const basegfx::B2DVector aScaledDirection(aDirection * fMedLength);
1739 // Bring Direction to correct length and apply
1740 roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + aScaledDirection));
1741 roPolygon.setPrevControlPoint(nIndex, basegfx::B2DPoint(aPoint - aScaledDirection));
1747 // convert to basegfx::B2DPolygon and return
1748 basegfx::B2DPolygon Polygon::getB2DPolygon() const
1750 basegfx::B2DPolygon aRetval;
1751 const sal_uInt16 nCount(mpImplPolygon->mnPoints);
1753 if(nCount)
1755 if(mpImplPolygon->mpFlagAry)
1757 // handling for curves. Add start point
1758 const Point aStartPoint(mpImplPolygon->mpPointAry[0]);
1759 sal_uInt8 nPointFlag(mpImplPolygon->mpFlagAry[0]);
1760 aRetval.append(basegfx::B2DPoint(aStartPoint.X(), aStartPoint.Y()));
1761 Point aControlA, aControlB;
1763 for(sal_uInt16 a(1); a < nCount;)
1765 bool bControlA(false);
1766 bool bControlB(false);
1768 if(POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
1770 aControlA = mpImplPolygon->mpPointAry[a++];
1771 bControlA = true;
1774 if(a < nCount && POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
1776 aControlB = mpImplPolygon->mpPointAry[a++];
1777 bControlB = true;
1780 // assert invalid polygons
1781 OSL_ENSURE(bControlA == bControlB, "Polygon::getB2DPolygon: Invalid source polygon (!)");
1782 (void)bControlB;
1784 if(a < nCount)
1786 const Point aEndPoint(mpImplPolygon->mpPointAry[a]);
1788 if(bControlA)
1790 // bezier edge, add
1791 aRetval.appendBezierSegment(
1792 basegfx::B2DPoint(aControlA.X(), aControlA.Y()),
1793 basegfx::B2DPoint(aControlB.X(), aControlB.Y()),
1794 basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
1796 impCorrectContinuity(aRetval, aRetval.count() - 2, nPointFlag);
1798 else
1800 // no bezier edge, add end point
1801 aRetval.append(basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
1804 nPointFlag = mpImplPolygon->mpFlagAry[a++];
1808 // if exist, remove double first/last points, set closed and correct control points
1809 basegfx::tools::checkClosed(aRetval);
1811 if(aRetval.isClosed())
1813 // closeWithGeometryChange did really close, so last point(s) were removed.
1814 // Correct the continuity in the changed point
1815 impCorrectContinuity(aRetval, 0, mpImplPolygon->mpFlagAry[0]);
1818 else
1820 // extra handling for non-curves (most-used case) for speedup
1821 for(sal_uInt16 a(0); a < nCount; a++)
1823 // get point and add
1824 const Point aPoint(mpImplPolygon->mpPointAry[a]);
1825 aRetval.append(basegfx::B2DPoint(aPoint.X(), aPoint.Y()));
1828 // set closed flag
1829 basegfx::tools::checkClosed(aRetval);
1833 return aRetval;
1836 // constructor to convert from basegfx::B2DPolygon
1837 // #i76891# Needed to change from adding all control points (even for unused
1838 // edges) and creating a fixed-size Polygon in the first run to creating the
1839 // minimal Polygon. This requires a temporary Point- and Flag-Array for curves
1840 // and a memcopy at ImplPolygon creation, but contains no zero-controlpoints
1841 // for straight edges.
1842 Polygon::Polygon(const basegfx::B2DPolygon& rPolygon)
1843 : mpImplPolygon(0)
1845 DBG_CTOR( Polygon, NULL );
1847 const bool bCurve(rPolygon.areControlPointsUsed());
1848 const bool bClosed(rPolygon.isClosed());
1849 sal_uInt32 nB2DLocalCount(rPolygon.count());
1851 if(bCurve)
1853 // #127979# Reduce source point count hard to the limit of the tools Polygon
1854 if(nB2DLocalCount > ((0x0000ffff / 3L) - 1L))
1856 OSL_FAIL("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
1857 nB2DLocalCount = ((0x0000ffff / 3L) - 1L);
1860 // calculate target point count
1861 const sal_uInt32 nLoopCount(bClosed ? nB2DLocalCount : (nB2DLocalCount ? nB2DLocalCount - 1L : 0L ));
1863 if(nLoopCount)
1865 // calculate maximum array size and allocate; prepare insert index
1866 const sal_uInt32 nMaxTargetCount((nLoopCount * 3) + 1);
1867 mpImplPolygon = new ImplPolygon(static_cast< sal_uInt16 >(nMaxTargetCount), true);
1869 // prepare insert index and current point
1870 sal_uInt32 nArrayInsert(0);
1871 basegfx::B2DCubicBezier aBezier;
1872 aBezier.setStartPoint(rPolygon.getB2DPoint(0));
1874 for(sal_uInt32 a(0L); a < nLoopCount; a++)
1876 // add current point (always) and remember StartPointIndex for evtl. later corrections
1877 const Point aStartPoint(FRound(aBezier.getStartPoint().getX()), FRound(aBezier.getStartPoint().getY()));
1878 const sal_uInt32 nStartPointIndex(nArrayInsert);
1879 mpImplPolygon->mpPointAry[nStartPointIndex] = aStartPoint;
1880 mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_NORMAL;
1881 nArrayInsert++;
1883 // prepare next segment
1884 const sal_uInt32 nNextIndex((a + 1) % nB2DLocalCount);
1885 aBezier.setEndPoint(rPolygon.getB2DPoint(nNextIndex));
1886 aBezier.setControlPointA(rPolygon.getNextControlPoint(a));
1887 aBezier.setControlPointB(rPolygon.getPrevControlPoint(nNextIndex));
1889 if(aBezier.isBezier())
1891 // if one is used, add always two control points due to the old schema
1892 mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointA().getX()), FRound(aBezier.getControlPointA().getY()));
1893 mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
1894 nArrayInsert++;
1896 mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointB().getX()), FRound(aBezier.getControlPointB().getY()));
1897 mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
1898 nArrayInsert++;
1901 // test continuity with previous control point to set flag value
1902 if(aBezier.getControlPointA() != aBezier.getStartPoint() && (bClosed || a))
1904 const basegfx::B2VectorContinuity eCont(rPolygon.getContinuityInPoint(a));
1906 if(basegfx::CONTINUITY_C1 == eCont)
1908 mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SMOOTH;
1910 else if(basegfx::CONTINUITY_C2 == eCont)
1912 mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SYMMTR;
1916 // prepare next polygon step
1917 aBezier.setStartPoint(aBezier.getEndPoint());
1920 if(bClosed)
1922 // add first point again as closing point due to old definition
1923 mpImplPolygon->mpPointAry[nArrayInsert] = mpImplPolygon->mpPointAry[0];
1924 mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
1925 nArrayInsert++;
1927 else
1929 // add last point as closing point
1930 const basegfx::B2DPoint aClosingPoint(rPolygon.getB2DPoint(nB2DLocalCount - 1L));
1931 const Point aEnd(FRound(aClosingPoint.getX()), FRound(aClosingPoint.getY()));
1932 mpImplPolygon->mpPointAry[nArrayInsert] = aEnd;
1933 mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
1934 nArrayInsert++;
1937 DBG_ASSERT(nArrayInsert <= nMaxTargetCount, "Polygon::Polygon from basegfx::B2DPolygon: wrong max point count estimation (!)");
1939 if(nArrayInsert != nMaxTargetCount)
1941 mpImplPolygon->ImplSetSize(static_cast< sal_uInt16 >(nArrayInsert), true);
1945 else
1947 // #127979# Reduce source point count hard to the limit of the tools Polygon
1948 if(nB2DLocalCount > (0x0000ffff - 1L))
1950 OSL_FAIL("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
1951 nB2DLocalCount = (0x0000ffff - 1L);
1954 if(nB2DLocalCount)
1956 // point list creation
1957 const sal_uInt32 nTargetCount(nB2DLocalCount + (bClosed ? 1L : 0L));
1958 mpImplPolygon = new ImplPolygon( static_cast< sal_uInt16 >(nTargetCount) );
1959 sal_uInt16 nIndex(0);
1961 for(sal_uInt32 a(0L); a < nB2DLocalCount; a++)
1963 basegfx::B2DPoint aB2DPoint(rPolygon.getB2DPoint(a));
1964 Point aPoint(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY()));
1965 mpImplPolygon->mpPointAry[nIndex++] = aPoint;
1968 if(bClosed)
1970 // add first point as closing point
1971 mpImplPolygon->mpPointAry[nIndex] = mpImplPolygon->mpPointAry[0];
1976 if(!mpImplPolygon)
1978 // no content yet, create empty polygon
1979 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
1983 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */