fix toolbar import
[ooovba.git] / tools / source / generic / poly.cxx
blob1d279225089957a736b4c1aad95b95dc50ea6cbb
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: poly.cxx,v $
10 * $Revision: 1.17 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_tools.hxx"
34 #define _SV_POLY_CXX
35 #include <osl/endian.h>
36 #include <tools/bigint.hxx>
37 #include <tools/debug.hxx>
38 #include <tools/stream.hxx>
39 #include <tools/vcompat.hxx>
40 #include <poly.h>
41 #include <tools/line.hxx>
42 #ifndef _VECTOR2D_H
43 #include <tools/vector2d.hxx>
44 #endif
45 #ifndef _POLY_HXX
46 #include <tools/poly.hxx>
47 #endif
48 #include <basegfx/polygon/b2dpolygon.hxx>
49 #include <basegfx/point/b2dpoint.hxx>
50 #include <basegfx/vector/b2dvector.hxx>
51 #include <basegfx/polygon/b2dpolygontools.hxx>
52 #include <basegfx/curve/b2dcubicbezier.hxx>
54 #include <vector>
55 #include <iterator>
56 #include <algorithm>
57 #include <cstring>
58 #include <limits.h>
59 #include <cmath>
62 // =======================================================================
64 DBG_NAME( Polygon )
66 // -----------------------------------------------------------------------
68 #define EDGE_LEFT 1
69 #define EDGE_TOP 2
70 #define EDGE_RIGHT 4
71 #define EDGE_BOTTOM 8
72 #define EDGE_HORZ (EDGE_RIGHT | EDGE_LEFT)
73 #define EDGE_VERT (EDGE_TOP | EDGE_BOTTOM)
74 #define SMALL_DVALUE 0.0000001
75 #define FSQRT2 1.4142135623730950488016887242097
77 // -----------------------------------------------------------------------
79 static ImplPolygonData aStaticImplPolygon =
81 NULL, NULL, 0, 0
84 // =======================================================================
86 ImplPolygon::ImplPolygon( USHORT nInitSize, BOOL bFlags )
88 if ( nInitSize )
90 mpPointAry = (Point*)new char[(ULONG)nInitSize*sizeof(Point)];
91 memset( mpPointAry, 0, (ULONG)nInitSize*sizeof(Point) );
93 else
94 mpPointAry = NULL;
96 if( bFlags )
98 mpFlagAry = new BYTE[ nInitSize ];
99 memset( mpPointAry, 0, nInitSize );
101 else
102 mpFlagAry = NULL;
104 mnRefCount = 1;
105 mnPoints = nInitSize;
108 // -----------------------------------------------------------------------
110 ImplPolygon::ImplPolygon( const ImplPolygon& rImpPoly )
112 if ( rImpPoly.mnPoints )
114 mpPointAry = (Point*)new char[(ULONG)rImpPoly.mnPoints*sizeof(Point)];
115 memcpy( mpPointAry, rImpPoly.mpPointAry, (ULONG)rImpPoly.mnPoints*sizeof(Point) );
117 if( rImpPoly.mpFlagAry )
119 mpFlagAry = new BYTE[ rImpPoly.mnPoints ];
120 memcpy( mpFlagAry, rImpPoly.mpFlagAry, rImpPoly.mnPoints );
122 else
123 mpFlagAry = NULL;
125 else
127 mpPointAry = NULL;
128 mpFlagAry = NULL;
131 mnRefCount = 1;
132 mnPoints = rImpPoly.mnPoints;
135 // -----------------------------------------------------------------------
137 ImplPolygon::ImplPolygon( USHORT nInitSize, const Point* pInitAry, const BYTE* pInitFlags )
139 if ( nInitSize )
141 mpPointAry = (Point*)new char[(ULONG)nInitSize*sizeof(Point)];
142 memcpy( mpPointAry, pInitAry, (ULONG)nInitSize*sizeof( Point ) );
144 if( pInitFlags )
146 mpFlagAry = new BYTE[ nInitSize ];
147 memcpy( mpFlagAry, pInitFlags, nInitSize );
149 else
150 mpFlagAry = NULL;
152 else
154 mpPointAry = NULL;
155 mpFlagAry = NULL;
158 mnRefCount = 1;
159 mnPoints = nInitSize;
162 // -----------------------------------------------------------------------
164 ImplPolygon::~ImplPolygon()
166 if ( mpPointAry )
168 delete[] (char*) mpPointAry;
171 if( mpFlagAry )
172 delete[] mpFlagAry;
175 // -----------------------------------------------------------------------
177 void ImplPolygon::ImplSetSize( USHORT nNewSize, BOOL bResize )
179 if( mnPoints == nNewSize )
180 return;
182 Point* pNewAry;
184 if ( nNewSize )
186 pNewAry = (Point*)new char[(ULONG)nNewSize*sizeof(Point)];
188 if ( bResize )
190 // Alte Punkte kopieren
191 if ( mnPoints < nNewSize )
193 // Neue Punkte mit 0 initialisieren
194 memset( pNewAry+mnPoints, 0, (ULONG)(nNewSize-mnPoints)*sizeof(Point) );
195 if ( mpPointAry )
196 memcpy( pNewAry, mpPointAry, mnPoints*sizeof(Point) );
198 else
200 if ( mpPointAry )
201 memcpy( pNewAry, mpPointAry, (ULONG)nNewSize*sizeof(Point) );
205 else
206 pNewAry = NULL;
208 if ( mpPointAry )
209 delete[] (char*) mpPointAry;
211 // ggf. FlagArray beruecksichtigen
212 if( mpFlagAry )
214 BYTE* pNewFlagAry;
216 if( nNewSize )
218 pNewFlagAry = new BYTE[ nNewSize ];
220 if( bResize )
222 // Alte Flags kopieren
223 if ( mnPoints < nNewSize )
225 // Neue Punkte mit 0 initialisieren
226 memset( pNewFlagAry+mnPoints, 0, nNewSize-mnPoints );
227 memcpy( pNewFlagAry, mpFlagAry, mnPoints );
229 else
230 memcpy( pNewFlagAry, mpFlagAry, nNewSize );
233 else
234 pNewFlagAry = NULL;
236 delete[] mpFlagAry;
237 mpFlagAry = pNewFlagAry;
240 mpPointAry = pNewAry;
241 mnPoints = nNewSize;
244 // -----------------------------------------------------------------------
246 void ImplPolygon::ImplSplit( USHORT nPos, USHORT nSpace, ImplPolygon* pInitPoly )
248 const ULONG nSpaceSize = nSpace * sizeof( Point );
249 const USHORT nNewSize = mnPoints + nSpace;
251 if( nPos >= mnPoints )
253 // Hinten anhaengen
254 nPos = mnPoints;
255 ImplSetSize( nNewSize, TRUE );
257 if( pInitPoly )
259 memcpy( mpPointAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
261 if( pInitPoly->mpFlagAry )
262 memcpy( mpFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
265 else
267 // PointArray ist in diesem Zweig immer vorhanden
268 const USHORT nSecPos = nPos + nSpace;
269 const USHORT nRest = mnPoints - nPos;
271 Point* pNewAry = (Point*) new char[ (ULONG) nNewSize * sizeof( Point ) ];
273 memcpy( pNewAry, mpPointAry, nPos * sizeof( Point ) );
275 if( pInitPoly )
276 memcpy( pNewAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
277 else
278 memset( pNewAry + nPos, 0, nSpaceSize );
280 memcpy( pNewAry + nSecPos, mpPointAry + nPos, nRest * sizeof( Point ) );
281 delete[] (char*) mpPointAry;
283 // ggf. FlagArray beruecksichtigen
284 if( mpFlagAry )
286 BYTE* pNewFlagAry = new BYTE[ nNewSize ];
288 memcpy( pNewFlagAry, mpFlagAry, nPos );
290 if( pInitPoly && pInitPoly->mpFlagAry )
291 memcpy( pNewFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
292 else
293 memset( pNewFlagAry + nPos, 0, nSpace );
295 memcpy( pNewFlagAry + nSecPos, mpFlagAry + nPos, nRest );
296 delete[] mpFlagAry;
297 mpFlagAry = pNewFlagAry;
300 mpPointAry = pNewAry;
301 mnPoints = nNewSize;
305 // -----------------------------------------------------------------------
307 void ImplPolygon::ImplRemove( USHORT nPos, USHORT nCount )
309 const USHORT nRemoveCount = Min( (USHORT) ( mnPoints - nPos ), (USHORT) nCount );
311 if( nRemoveCount )
313 const USHORT nNewSize = mnPoints - nRemoveCount;
314 const USHORT nSecPos = nPos + nRemoveCount;
315 const USHORT nRest = mnPoints - nSecPos;
317 Point* pNewAry = (Point*) new char[ (ULONG) nNewSize * sizeof( Point ) ];
319 memcpy( pNewAry, mpPointAry, nPos * sizeof( Point ) );
320 memcpy( pNewAry + nPos, mpPointAry + nSecPos, nRest * sizeof( Point ) );
322 delete[] (char*) mpPointAry;
324 // ggf. FlagArray beruecksichtigen
325 if( mpFlagAry )
327 BYTE* pNewFlagAry = new BYTE[ nNewSize ];
329 memcpy( pNewFlagAry, mpFlagAry, nPos );
330 memcpy( pNewFlagAry + nPos, mpFlagAry + nSecPos, nRest );
331 delete[] mpFlagAry;
332 mpFlagAry = pNewFlagAry;
335 mpPointAry = pNewAry;
336 mnPoints = nNewSize;
340 // -----------------------------------------------------------------------
342 void ImplPolygon::ImplCreateFlagArray()
344 if( !mpFlagAry )
346 mpFlagAry = new BYTE[ mnPoints ];
347 memset( mpFlagAry, 0, mnPoints );
351 // =======================================================================
353 inline void Polygon::ImplMakeUnique()
355 // Falls noch andere Referenzen bestehen, dann kopieren
356 if ( mpImplPolygon->mnRefCount != 1 )
358 if ( mpImplPolygon->mnRefCount )
359 mpImplPolygon->mnRefCount--;
360 mpImplPolygon = new ImplPolygon( *mpImplPolygon );
364 // -----------------------------------------------------------------------
366 inline double ImplGetAngle( const Point& rCenter, const Point& rPt )
368 const long nDX = rPt.X() - rCenter.X();
369 return( atan2( -rPt.Y() + rCenter.Y(), ( ( nDX == 0L ) ? 0.000000001 : nDX ) ) );
372 // -----------------------------------------------------------------------
374 Polygon::Polygon()
376 DBG_CTOR( Polygon, NULL );
377 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
380 // -----------------------------------------------------------------------
382 Polygon::Polygon( USHORT nSize )
384 DBG_CTOR( Polygon, NULL );
386 if ( nSize )
387 mpImplPolygon = new ImplPolygon( nSize );
388 else
389 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
392 // -----------------------------------------------------------------------
394 Polygon::Polygon( USHORT nPoints, const Point* pPtAry, const BYTE* pFlagAry )
396 DBG_CTOR( Polygon, NULL );
398 if( nPoints )
399 mpImplPolygon = new ImplPolygon( nPoints, pPtAry, pFlagAry );
400 else
401 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
404 // -----------------------------------------------------------------------
406 Polygon::Polygon( const Polygon& rPoly )
408 DBG_CTOR( Polygon, NULL );
409 DBG_CHKOBJ( &rPoly, Polygon, NULL );
410 DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
412 mpImplPolygon = rPoly.mpImplPolygon;
413 if ( mpImplPolygon->mnRefCount )
414 mpImplPolygon->mnRefCount++;
417 // -----------------------------------------------------------------------
419 Polygon::Polygon( const Rectangle& rRect )
421 DBG_CTOR( Polygon, NULL );
423 if ( rRect.IsEmpty() )
424 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
425 else
427 mpImplPolygon = new ImplPolygon( 5 );
428 mpImplPolygon->mpPointAry[0] = rRect.TopLeft();
429 mpImplPolygon->mpPointAry[1] = rRect.TopRight();
430 mpImplPolygon->mpPointAry[2] = rRect.BottomRight();
431 mpImplPolygon->mpPointAry[3] = rRect.BottomLeft();
432 mpImplPolygon->mpPointAry[4] = rRect.TopLeft();
436 // -----------------------------------------------------------------------
438 Polygon::Polygon( const Rectangle& rRect, ULONG nHorzRound, ULONG nVertRound )
440 DBG_CTOR( Polygon, NULL );
442 if ( rRect.IsEmpty() )
443 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
444 else
446 Rectangle aRect( rRect );
447 aRect.Justify(); // SJ: i9140
449 nHorzRound = Min( nHorzRound, (ULONG) labs( aRect.GetWidth() >> 1 ) );
450 nVertRound = Min( nVertRound, (ULONG) labs( aRect.GetHeight() >> 1 ) );
452 if( !nHorzRound && !nVertRound )
454 mpImplPolygon = new ImplPolygon( 5 );
455 mpImplPolygon->mpPointAry[0] = aRect.TopLeft();
456 mpImplPolygon->mpPointAry[1] = aRect.TopRight();
457 mpImplPolygon->mpPointAry[2] = aRect.BottomRight();
458 mpImplPolygon->mpPointAry[3] = aRect.BottomLeft();
459 mpImplPolygon->mpPointAry[4] = aRect.TopLeft();
461 else
463 const Point aTL( aRect.Left() + nHorzRound, aRect.Top() + nVertRound );
464 const Point aTR( aRect.Right() - nHorzRound, aRect.Top() + nVertRound );
465 const Point aBR( aRect.Right() - nHorzRound, aRect.Bottom() - nVertRound );
466 const Point aBL( aRect.Left() + nHorzRound, aRect.Bottom() - nVertRound );
467 Polygon* pEllipsePoly = new Polygon( Point(), nHorzRound, nVertRound );
468 USHORT i, nEnd, nSize4 = pEllipsePoly->GetSize() >> 2;
470 mpImplPolygon = new ImplPolygon( pEllipsePoly->GetSize() + 1 );
472 const Point* pSrcAry = pEllipsePoly->GetConstPointAry();
473 Point* pDstAry = mpImplPolygon->mpPointAry;
475 for( i = 0, nEnd = nSize4; i < nEnd; i++ )
476 ( pDstAry[ i ] = pSrcAry[ i ] ) += aTR;
478 for( nEnd = nEnd + nSize4; i < nEnd; i++ )
479 ( pDstAry[ i ] = pSrcAry[ i ] ) += aTL;
481 for( nEnd = nEnd + nSize4; i < nEnd; i++ )
482 ( pDstAry[ i ] = pSrcAry[ i ] ) += aBL;
484 for( nEnd = nEnd + nSize4; i < nEnd; i++ )
485 ( pDstAry[ i ] = pSrcAry[ i ] ) += aBR;
487 pDstAry[ nEnd ] = pDstAry[ 0 ];
488 delete pEllipsePoly;
493 // -----------------------------------------------------------------------
495 Polygon::Polygon( const Point& rCenter, long nRadX, long nRadY, USHORT nPoints )
497 DBG_CTOR( Polygon, NULL );
499 if( nRadX && nRadY )
501 // Default berechnen (abhaengig von Groesse)
502 if( !nPoints )
504 nPoints = (USHORT) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
505 sqrt( (double) labs( nRadX * nRadY ) ) ) );
507 nPoints = (USHORT) MinMax( nPoints, 32, 256 );
509 if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
510 nPoints >>= 1;
513 // Anzahl der Punkte auf durch 4 teilbare Zahl aufrunden
514 mpImplPolygon = new ImplPolygon( nPoints = (nPoints + 3) & ~3 );
516 Point* pPt;
517 USHORT i;
518 USHORT nPoints2 = nPoints >> 1;
519 USHORT nPoints4 = nPoints >> 2;
520 double nAngle;
521 double nAngleStep = F_PI2 / ( nPoints4 - 1 );
523 for( i=0, nAngle = 0.0; i < nPoints4; i++, nAngle += nAngleStep )
525 long nX = FRound( nRadX * cos( nAngle ) );
526 long nY = FRound( -nRadY * sin( nAngle ) );
528 pPt = &(mpImplPolygon->mpPointAry[i]);
529 pPt->X() = nX + rCenter.X();
530 pPt->Y() = nY + rCenter.Y();
531 pPt = &(mpImplPolygon->mpPointAry[nPoints2-i-1]);
532 pPt->X() = -nX + rCenter.X();
533 pPt->Y() = nY + rCenter.Y();
534 pPt = &(mpImplPolygon->mpPointAry[i+nPoints2]);
535 pPt->X() = -nX + rCenter.X();
536 pPt->Y() = -nY + rCenter.Y();
537 pPt = &(mpImplPolygon->mpPointAry[nPoints-i-1]);
538 pPt->X() = nX + rCenter.X();
539 pPt->Y() = -nY + rCenter.Y();
542 else
543 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
546 // -----------------------------------------------------------------------
548 Polygon::Polygon( const Rectangle& rBound,
549 const Point& rStart, const Point& rEnd, PolyStyle eStyle )
551 DBG_CTOR( Polygon, NULL );
553 const long nWidth = rBound.GetWidth();
554 const long nHeight = rBound.GetHeight();
556 if( ( nWidth > 1 ) && ( nHeight > 1 ) )
558 const Point aCenter( rBound.Center() );
559 const long nRadX = aCenter.X() - rBound.Left();
560 const long nRadY = aCenter.Y() - rBound.Top();
561 USHORT nPoints;
563 nPoints = (USHORT) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
564 sqrt( (double) labs( nRadX * nRadY ) ) ) );
566 nPoints = (USHORT) MinMax( nPoints, 32, 256 );
568 if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
569 nPoints >>= 1;
571 // Winkel berechnen
572 const double fRadX = nRadX;
573 const double fRadY = nRadY;
574 const double fCenterX = aCenter.X();
575 const double fCenterY = aCenter.Y();
576 double fStart = ImplGetAngle( aCenter, rStart );
577 double fEnd = ImplGetAngle( aCenter, rEnd );
578 double fDiff = fEnd - fStart;
579 double fStep;
580 USHORT nStart;
581 USHORT nEnd;
583 if( fDiff < 0. )
584 fDiff += F_2PI;
586 // Punktanzahl proportional verkleinern ( fDiff / (2PI) );
587 // ist eingentlich nur fuer einen Kreis richtig; wir
588 // machen es hier aber trotzdem
589 nPoints = Max( (USHORT) ( ( fDiff * 0.1591549 ) * nPoints ), (USHORT) 16 );
590 fStep = fDiff / ( nPoints - 1 );
592 if( POLY_PIE == eStyle )
594 const Point aCenter2( FRound( fCenterX ), FRound( fCenterY ) );
596 nStart = 1;
597 nEnd = nPoints + 1;
598 mpImplPolygon = new ImplPolygon( nPoints + 2 );
599 mpImplPolygon->mpPointAry[ 0 ] = aCenter2;
600 mpImplPolygon->mpPointAry[ nEnd ] = aCenter2;
602 else
604 mpImplPolygon = new ImplPolygon( ( POLY_CHORD == eStyle ) ? ( nPoints + 1 ) : nPoints );
605 nStart = 0;
606 nEnd = nPoints;
609 for(; nStart < nEnd; nStart++, fStart += fStep )
611 Point& rPt = mpImplPolygon->mpPointAry[ nStart ];
613 rPt.X() = FRound( fCenterX + fRadX * cos( fStart ) );
614 rPt.Y() = FRound( fCenterY - fRadY * sin( fStart ) );
617 if( POLY_CHORD == eStyle )
618 mpImplPolygon->mpPointAry[ nPoints ] = mpImplPolygon->mpPointAry[ 0 ];
620 else
621 mpImplPolygon = (ImplPolygon*) &aStaticImplPolygon;
624 // -----------------------------------------------------------------------
626 Polygon::Polygon( const Point& rBezPt1, const Point& rCtrlPt1,
627 const Point& rBezPt2, const Point& rCtrlPt2,
628 USHORT nPoints )
630 DBG_CTOR( Polygon, NULL );
632 nPoints = ( 0 == nPoints ) ? 25 : ( ( nPoints < 2 ) ? 2 : nPoints );
634 const double fInc = 1.0 / ( nPoints - 1 );
635 double fK_1 = 0.0, fK1_1 = 1.0;
636 double fK_2, fK_3, fK1_2, fK1_3, fK12, fK21;
637 const double fX0 = rBezPt1.X();
638 const double fY0 = rBezPt1.Y();
639 const double fX1 = 3.0 * rCtrlPt1.X();
640 const double fY1 = 3.0 * rCtrlPt1.Y();
641 const double fX2 = 3.0 * rCtrlPt2.X();;
642 const double fY2 = 3.0 * rCtrlPt2.Y();;
643 const double fX3 = rBezPt2.X();
644 const double fY3 = rBezPt2.Y();
646 mpImplPolygon = new ImplPolygon( nPoints );
648 for( USHORT i = 0; i < nPoints; i++, fK_1 += fInc, fK1_1 -= fInc )
650 Point& rPt = mpImplPolygon->mpPointAry[ i ];
652 fK_2 = fK_1, fK_3 = ( fK_2 *= fK_1 ), fK_3 *= fK_1;
653 fK1_2 = fK1_1, fK1_3 = ( fK1_2 *= fK1_1 ), fK1_3 *= fK1_1;
654 fK12 = fK_1 * fK1_2, fK21 = fK_2 * fK1_1;
656 rPt.X() = FRound( fK1_3 * fX0 + fK12 * fX1 + fK21 * fX2 + fK_3 * fX3 );
657 rPt.Y() = FRound( fK1_3 * fY0 + fK12 * fY1 + fK21 * fY2 + fK_3 * fY3 );
661 // -----------------------------------------------------------------------
663 Polygon::~Polygon()
665 DBG_DTOR( Polygon, NULL );
667 // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
668 // die letzte Referenz ist, sonst Referenzcounter decrementieren
669 if ( mpImplPolygon->mnRefCount )
671 if ( mpImplPolygon->mnRefCount > 1 )
672 mpImplPolygon->mnRefCount--;
673 else
674 delete mpImplPolygon;
678 // -----------------------------------------------------------------------
680 Point* Polygon::ImplGetPointAry()
682 DBG_CHKTHIS( Polygon, NULL );
684 ImplMakeUnique();
685 return (Point*)mpImplPolygon->mpPointAry;
688 // -----------------------------------------------------------------------
690 BYTE* Polygon::ImplGetFlagAry()
692 DBG_CHKTHIS( Polygon, NULL );
694 ImplMakeUnique();
695 mpImplPolygon->ImplCreateFlagArray();
696 return mpImplPolygon->mpFlagAry;
699 // -----------------------------------------------------------------------
701 const Point* Polygon::GetConstPointAry() const
703 DBG_CHKTHIS( Polygon, NULL );
704 return (Point*)mpImplPolygon->mpPointAry;
707 // -----------------------------------------------------------------------
709 const BYTE* Polygon::GetConstFlagAry() const
711 DBG_CHKTHIS( Polygon, NULL );
712 return mpImplPolygon->mpFlagAry;
715 // -----------------------------------------------------------------------
717 void Polygon::SetPoint( const Point& rPt, USHORT nPos )
719 DBG_CHKTHIS( Polygon, NULL );
720 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
721 "Polygon::SetPoint(): nPos >= nPoints" );
723 ImplMakeUnique();
724 mpImplPolygon->mpPointAry[nPos] = rPt;
727 // -----------------------------------------------------------------------
729 void Polygon::SetFlags( USHORT nPos, PolyFlags eFlags )
731 DBG_CHKTHIS( Polygon, NULL );
732 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
733 "Polygon::SetFlags(): nPos >= nPoints" );
735 // we do only want to create the flag array if there
736 // is at least one flag different to POLY_NORMAL
737 if ( mpImplPolygon || ( eFlags != POLY_NORMAL ) )
739 ImplMakeUnique();
740 mpImplPolygon->ImplCreateFlagArray();
741 mpImplPolygon->mpFlagAry[ nPos ] = (BYTE) eFlags;
745 // -----------------------------------------------------------------------
747 const Point& Polygon::GetPoint( USHORT nPos ) const
749 DBG_CHKTHIS( Polygon, NULL );
750 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
751 "Polygon::GetPoint(): nPos >= nPoints" );
753 return mpImplPolygon->mpPointAry[nPos];
756 // -----------------------------------------------------------------------
758 PolyFlags Polygon::GetFlags( USHORT nPos ) const
760 DBG_CHKTHIS( Polygon, NULL );
761 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
762 "Polygon::GetFlags(): nPos >= nPoints" );
763 return( mpImplPolygon->mpFlagAry ?
764 (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] :
765 POLY_NORMAL );
768 // -----------------------------------------------------------------------
770 sal_Bool Polygon::HasFlags() const
772 return mpImplPolygon->mpFlagAry != NULL;
775 // -----------------------------------------------------------------------
777 BOOL Polygon::IsControl(USHORT nPos) const
779 DBG_CHKTHIS( Polygon, NULL );
780 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
781 "Polygon::GetFlags(): nPos >= nPoints" );
782 PolyFlags eFlags = mpImplPolygon->mpFlagAry ?
783 (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] : POLY_NORMAL;
785 return( POLY_CONTROL == eFlags );
788 // -----------------------------------------------------------------------
790 BOOL Polygon::IsSmooth(USHORT nPos) const
792 DBG_CHKTHIS( Polygon, NULL );
793 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
794 "Polygon::GetFlags(): nPos >= nPoints" );
795 PolyFlags eFlags = mpImplPolygon->mpFlagAry ?
796 (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] : POLY_NORMAL;
798 return( ( POLY_SMOOTH == eFlags ) || ( POLY_SYMMTR == eFlags ) );
801 // -----------------------------------------------------------------------
803 BOOL Polygon::IsRect() const
805 BOOL bIsRect = FALSE;
806 if ( mpImplPolygon->mpFlagAry == NULL )
808 if ( ( ( mpImplPolygon->mnPoints == 5 ) && ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ 4 ] ) ) ||
809 ( mpImplPolygon->mnPoints == 4 ) )
811 if ( ( mpImplPolygon->mpPointAry[ 0 ].X() == mpImplPolygon->mpPointAry[ 3 ].X() ) &&
812 ( mpImplPolygon->mpPointAry[ 0 ].Y() == mpImplPolygon->mpPointAry[ 1 ].Y() ) &&
813 ( mpImplPolygon->mpPointAry[ 1 ].X() == mpImplPolygon->mpPointAry[ 2 ].X() ) &&
814 ( mpImplPolygon->mpPointAry[ 2 ].Y() == mpImplPolygon->mpPointAry[ 3 ].Y() ) )
815 bIsRect = TRUE;
818 return bIsRect;
821 // -----------------------------------------------------------------------
823 void Polygon::SetSize( USHORT nNewSize )
825 DBG_CHKTHIS( Polygon, NULL );
827 if( nNewSize != mpImplPolygon->mnPoints )
829 ImplMakeUnique();
830 mpImplPolygon->ImplSetSize( nNewSize );
834 // -----------------------------------------------------------------------
836 USHORT Polygon::GetSize() const
838 DBG_CHKTHIS( Polygon, NULL );
840 return mpImplPolygon->mnPoints;
843 // -----------------------------------------------------------------------
845 void Polygon::Clear()
847 DBG_CHKTHIS( Polygon, NULL );
849 if ( mpImplPolygon->mnRefCount )
851 if ( mpImplPolygon->mnRefCount > 1 )
852 mpImplPolygon->mnRefCount--;
853 else
854 delete mpImplPolygon;
857 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
860 // -----------------------------------------------------------------------
862 double Polygon::CalcDistance( USHORT nP1, USHORT nP2 )
864 DBG_ASSERT( nP1 < mpImplPolygon->mnPoints,
865 "Polygon::CalcDistance(): nPos1 >= nPoints" );
866 DBG_ASSERT( nP2 < mpImplPolygon->mnPoints,
867 "Polygon::CalcDistance(): nPos2 >= nPoints" );
869 const Point& rP1 = mpImplPolygon->mpPointAry[ nP1 ];
870 const Point& rP2 = mpImplPolygon->mpPointAry[ nP2 ];
871 const double fDx = rP2.X() - rP1.X();
872 const double fDy = rP2.Y() - rP1.Y();
874 return sqrt( fDx * fDx + fDy * fDy );
877 // -----------------------------------------------------------------------
879 void Polygon::Optimize( ULONG nOptimizeFlags, const PolyOptimizeData* pData )
881 DBG_CHKTHIS( Polygon, NULL );
882 DBG_ASSERT( !mpImplPolygon->mpFlagAry, "Optimizing could fail with beziers!" );
884 USHORT nSize = mpImplPolygon->mnPoints;
886 if( nOptimizeFlags && nSize )
888 if( nOptimizeFlags & POLY_OPTIMIZE_EDGES )
890 const Rectangle aBound( GetBoundRect() );
891 const double fArea = ( aBound.GetWidth() + aBound.GetHeight() ) * 0.5;
892 const USHORT nPercent = pData ? pData->GetPercentValue() : 50;
894 Optimize( POLY_OPTIMIZE_NO_SAME );
895 ImplReduceEdges( *this, fArea, nPercent );
897 else if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE | POLY_OPTIMIZE_NO_SAME ) )
899 Polygon aNewPoly;
900 const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
901 ULONG nReduce;
903 if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE ) )
904 nReduce = pData ? pData->GetAbsValue() : 4UL;
905 else
906 nReduce = 0UL;
908 while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
909 nSize--;
911 if( nSize > 1 )
913 USHORT nLast = 0, nNewCount = 1;
915 aNewPoly.SetSize( nSize );
916 aNewPoly[ 0 ] = rFirst;
918 for( USHORT i = 1; i < nSize; i++ )
920 if( ( mpImplPolygon->mpPointAry[ i ] != mpImplPolygon->mpPointAry[ nLast ] ) &&
921 ( !nReduce || ( nReduce < (ULONG) FRound( CalcDistance( nLast, i ) ) ) ) )
923 aNewPoly[ nNewCount++ ] = mpImplPolygon->mpPointAry[ nLast = i ];
927 if( nNewCount == 1 )
928 aNewPoly.Clear();
929 else
930 aNewPoly.SetSize( nNewCount );
933 *this = aNewPoly;
936 nSize = mpImplPolygon->mnPoints;
938 if( nSize > 1 )
940 if( ( nOptimizeFlags & POLY_OPTIMIZE_CLOSE ) &&
941 ( mpImplPolygon->mpPointAry[ 0 ] != mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
943 SetSize( mpImplPolygon->mnPoints + 1 );
944 mpImplPolygon->mpPointAry[ mpImplPolygon->mnPoints - 1 ] = mpImplPolygon->mpPointAry[ 0 ];
946 else if( ( nOptimizeFlags & POLY_OPTIMIZE_OPEN ) &&
947 ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
949 const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
951 while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
952 nSize--;
954 SetSize( nSize );
960 // -----------------------------------------------------------------------
962 void Polygon::GetSimple( Polygon& rResult ) const
964 if( !mpImplPolygon->mpFlagAry )
965 rResult = *this;
966 else
968 ::std::vector< Point > aPointVector;
970 for( USHORT i = 0, nCount = GetSize(); i < nCount; )
972 if( ( ( i + 3 ) < nCount ) &&
973 ( POLY_NORMAL == mpImplPolygon->mpFlagAry[ i ] ) &&
974 ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 1 ] ) &&
975 ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 2 ] ) &&
976 ( POLY_NORMAL == mpImplPolygon->mpFlagAry[ i + 3 ] ) )
978 const USHORT nSegmentPoints = 25;
979 const Polygon aSegmentPoly( mpImplPolygon->mpPointAry[ i ], mpImplPolygon->mpPointAry[ i + 1 ],
980 mpImplPolygon->mpPointAry[ i + 3 ], mpImplPolygon->mpPointAry[ i + 2 ],
981 nSegmentPoints );
982 const USHORT nSegmentSize = aSegmentPoly.GetSize();
984 if( nSegmentSize )
986 const Point* pPointArray = aSegmentPoly.mpImplPolygon->mpPointAry;
987 const Point* pCur = pPointArray;
988 const Point* pLast;
990 aPointVector.push_back( *( pLast = pCur ) );
992 for( USHORT j = 1; j < nSegmentSize; j++ )
993 if( *( pCur = pPointArray + j ) != *pLast )
994 aPointVector.push_back( *( pLast = pCur ) );
997 i += 3;
999 else
1000 aPointVector.push_back( mpImplPolygon->mpPointAry[ i++ ] );
1003 // fill result polygon
1004 rResult = Polygon( (USHORT)aPointVector.size() );
1005 ::std::vector< Point >::iterator aIter( aPointVector.begin() ), aEnd( aPointVector.end() );
1006 Point* pPointArray = rResult.mpImplPolygon->mpPointAry;
1008 while( aIter != aEnd )
1009 *pPointArray++ = *aIter++;
1013 // =======================================================================
1015 /* Recursively subdivide cubic bezier curve via deCasteljau.
1017 @param rPointIter
1018 Output iterator, where the subdivided polylines are written to.
1020 @param d
1021 Squared difference of curve to a straight line
1023 @param P*
1024 Exactly four points, interpreted as support and control points of
1025 a cubic bezier curve. Must be in device coordinates, since stop
1026 criterion is based on the following assumption: the device has a
1027 finite resolution, it is thus sufficient to stop subdivision if the
1028 curve does not deviate more than one pixel from a straight line.
1031 static void ImplAdaptiveSubdivide( ::std::back_insert_iterator< ::std::vector< Point > >& rPointIter,
1032 const double old_d2,
1033 int recursionDepth,
1034 const double d2,
1035 const double P1x, const double P1y,
1036 const double P2x, const double P2y,
1037 const double P3x, const double P3y,
1038 const double P4x, const double P4y )
1040 // Hard limit on recursion depth, empiric number.
1041 enum {maxRecursionDepth=128};
1043 // Perform bezier flatness test (lecture notes from R. Schaback,
1044 // Mathematics of Computer-Aided Design, Uni Goettingen, 2000)
1046 // ||P(t) - L(t)|| <= max ||b_j - b_0 - j/n(b_n - b_0)||
1047 // 0<=j<=n
1049 // What is calculated here is an upper bound to the distance from
1050 // a line through b_0 and b_3 (P1 and P4 in our notation) and the
1051 // curve. We can drop 0 and n from the running indices, since the
1052 // argument of max becomes zero for those cases.
1053 const double fJ1x( P2x - P1x - 1.0/3.0*(P4x - P1x) );
1054 const double fJ1y( P2y - P1y - 1.0/3.0*(P4y - P1y) );
1055 const double fJ2x( P3x - P1x - 2.0/3.0*(P4x - P1x) );
1056 const double fJ2y( P3y - P1y - 2.0/3.0*(P4y - P1y) );
1057 const double distance2( ::std::max( fJ1x*fJ1x + fJ1y*fJ1y,
1058 fJ2x*fJ2x + fJ2y*fJ2y) );
1060 // stop if error measure does not improve anymore. This is a
1061 // safety guard against floating point inaccuracies.
1062 // stop at recursion level 128. This is a safety guard against
1063 // floating point inaccuracies.
1064 // stop if distance from line is guaranteed to be bounded by d
1065 if( old_d2 > d2 &&
1066 recursionDepth < maxRecursionDepth &&
1067 distance2 >= d2 )
1069 // deCasteljau bezier arc, split at t=0.5
1070 // Foley/vanDam, p. 508
1071 const double L1x( P1x ), L1y( P1y );
1072 const double L2x( (P1x + P2x)*0.5 ), L2y( (P1y + P2y)*0.5 );
1073 const double Hx ( (P2x + P3x)*0.5 ), Hy ( (P2y + P3y)*0.5 );
1074 const double L3x( (L2x + Hx)*0.5 ), L3y( (L2y + Hy)*0.5 );
1075 const double R4x( P4x ), R4y( P4y );
1076 const double R3x( (P3x + P4x)*0.5 ), R3y( (P3y + P4y)*0.5 );
1077 const double R2x( (Hx + R3x)*0.5 ), R2y( (Hy + R3y)*0.5 );
1078 const double R1x( (L3x + R2x)*0.5 ), R1y( (L3y + R2y)*0.5 );
1079 const double L4x( R1x ), L4y( R1y );
1081 // subdivide further
1082 ++recursionDepth;
1083 ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, L1x, L1y, L2x, L2y, L3x, L3y, L4x, L4y);
1084 ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, R1x, R1y, R2x, R2y, R3x, R3y, R4x, R4y);
1086 else
1088 // requested resolution reached.
1089 // Add end points to output iterator.
1090 // order is preserved, since this is so to say depth first traversal.
1091 *rPointIter++ = Point( FRound(P1x), FRound(P1y) );
1095 // =======================================================================
1097 void Polygon::AdaptiveSubdivide( Polygon& rResult, const double d ) const
1099 if( !mpImplPolygon->mpFlagAry )
1101 rResult = *this;
1103 else
1105 USHORT i;
1106 USHORT nPts( GetSize() );
1107 ::std::vector< Point > aPoints;
1108 aPoints.reserve( nPts );
1109 ::std::back_insert_iterator< ::std::vector< Point > > aPointIter( aPoints );
1111 for(i=0; i<nPts;)
1113 if( ( i + 3 ) < nPts )
1115 BYTE P1( mpImplPolygon->mpFlagAry[ i ] );
1116 BYTE P4( mpImplPolygon->mpFlagAry[ i + 3 ] );
1118 if( ( POLY_NORMAL == P1 || POLY_SMOOTH == P1 || POLY_SYMMTR == P1 ) &&
1119 ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 1 ] ) &&
1120 ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 2 ] ) &&
1121 ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
1123 ImplAdaptiveSubdivide( aPointIter, d*d+1.0, 0, d*d,
1124 mpImplPolygon->mpPointAry[ i ].X(), mpImplPolygon->mpPointAry[ i ].Y(),
1125 mpImplPolygon->mpPointAry[ i+1 ].X(), mpImplPolygon->mpPointAry[ i+1 ].Y(),
1126 mpImplPolygon->mpPointAry[ i+2 ].X(), mpImplPolygon->mpPointAry[ i+2 ].Y(),
1127 mpImplPolygon->mpPointAry[ i+3 ].X(), mpImplPolygon->mpPointAry[ i+3 ].Y() );
1128 i += 3;
1129 continue;
1133 *aPointIter++ = mpImplPolygon->mpPointAry[ i++ ];
1136 // fill result polygon
1137 rResult = Polygon( (USHORT)aPoints.size() ); // ensure sufficient size for copy
1138 ::std::copy(aPoints.begin(), aPoints.end(), rResult.mpImplPolygon->mpPointAry);
1142 // -----------------------------------------------------------------------
1144 void Polygon::GetIntersection( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1146 const PolyPolygon aTmp( *this );
1147 aTmp.GetIntersection( rPolyPoly, rResult );
1150 // -----------------------------------------------------------------------
1152 void Polygon::GetUnion( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1154 const PolyPolygon aTmp( *this );
1155 aTmp.GetUnion( rPolyPoly, rResult );
1158 // -----------------------------------------------------------------------
1160 void Polygon::GetDifference( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1162 const PolyPolygon aTmp( *this );
1163 aTmp.GetDifference( rPolyPoly, rResult );
1166 // -----------------------------------------------------------------------
1168 void Polygon::GetXOR( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1170 const PolyPolygon aTmp( *this );
1171 aTmp.GetXOR( rPolyPoly, rResult );
1174 // -----------------------------------------------------------------------
1176 void Polygon::ImplReduceEdges( Polygon& rPoly, const double& rArea, USHORT nPercent )
1178 const double fBound = 2000.0 * ( 100 - nPercent ) * 0.01;
1179 USHORT nNumNoChange = 0, nNumRuns = 0;
1181 while( nNumNoChange < 2 )
1183 USHORT nPntCnt = rPoly.GetSize(), nNewPos = 0;
1184 Polygon aNewPoly( nPntCnt );
1185 BOOL bChangeInThisRun = FALSE;
1187 for( USHORT n = 0; n < nPntCnt; n++ )
1189 BOOL bDeletePoint = FALSE;
1191 if( ( n + nNumRuns ) % 2 )
1193 USHORT nIndPrev = !n ? nPntCnt - 1 : n - 1;
1194 USHORT nIndPrevPrev = !nIndPrev ? nPntCnt - 1 : nIndPrev - 1;
1195 USHORT nIndNext = ( n == nPntCnt-1 ) ? 0 : n + 1;
1196 USHORT nIndNextNext = ( nIndNext == nPntCnt - 1 ) ? 0 : nIndNext + 1;
1197 Vector2D aVec1( rPoly[ nIndPrev ] ); aVec1 -= rPoly[ nIndPrevPrev ];
1198 Vector2D aVec2( rPoly[ n ] ); aVec2 -= rPoly[ nIndPrev ];
1199 Vector2D aVec3( rPoly[ nIndNext ] ); aVec3 -= rPoly[ n ];
1200 Vector2D aVec4( rPoly[ nIndNextNext ] ); aVec4 -= rPoly[ nIndNext ];
1201 double fDist1 = aVec1.GetLength(), fDist2 = aVec2.GetLength();
1202 double fDist3 = aVec3.GetLength(), fDist4 = aVec4.GetLength();
1203 double fTurnB = aVec2.Normalize().Scalar( aVec3.Normalize() );
1205 if( fabs( fTurnB ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnB ) > ( 1.0 - SMALL_DVALUE ) )
1206 bDeletePoint = TRUE;
1207 else
1209 Vector2D aVecB( rPoly[ nIndNext ] );
1210 double fDistB = ( aVecB -= rPoly[ nIndPrev ] ).GetLength();
1211 double fLenWithB = fDist2 + fDist3;
1212 double fLenFact = ( fDistB != 0.0 ) ? fLenWithB / fDistB : 1.0;
1213 double fTurnPrev = aVec1.Normalize().Scalar( aVec2 );
1214 double fTurnNext = aVec3.Scalar( aVec4.Normalize() );
1215 double fGradPrev, fGradB, fGradNext;
1217 if( fabs( fTurnPrev ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnPrev ) > ( 1.0 - SMALL_DVALUE ) )
1218 fGradPrev = 0.0;
1219 else
1220 fGradPrev = acos( fTurnPrev ) / ( aVec1.IsNegative( aVec2 ) ? -F_PI180 : F_PI180 );
1222 fGradB = acos( fTurnB ) / ( aVec2.IsNegative( aVec3 ) ? -F_PI180 : F_PI180 );
1224 if( fabs( fTurnNext ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnNext ) > ( 1.0 - SMALL_DVALUE ) )
1225 fGradNext = 0.0;
1226 else
1227 fGradNext = acos( fTurnNext ) / ( aVec3.IsNegative( aVec4 ) ? -F_PI180 : F_PI180 );
1229 if( ( fGradPrev > 0.0 && fGradB < 0.0 && fGradNext > 0.0 ) ||
1230 ( fGradPrev < 0.0 && fGradB > 0.0 && fGradNext < 0.0 ) )
1232 if( ( fLenFact < ( FSQRT2 + SMALL_DVALUE ) ) &&
1233 ( ( ( fDist1 + fDist4 ) / ( fDist2 + fDist3 ) ) * 2000.0 ) > fBound )
1235 bDeletePoint = TRUE;
1238 else
1240 double fRelLen = 1.0 - sqrt( fDistB / rArea );
1242 if( fRelLen < 0.0 )
1243 fRelLen = 0.0;
1244 else if( fRelLen > 1.0 )
1245 fRelLen = 1.0;
1247 if( ( (UINT32) ( ( ( fLenFact - 1.0 ) * 1000000.0 ) + 0.5 ) < fBound ) &&
1248 ( fabs( fGradB ) <= ( fRelLen * fBound * 0.01 ) ) )
1250 bDeletePoint = TRUE;
1256 if( !bDeletePoint )
1257 aNewPoly[ nNewPos++ ] = rPoly[ n ];
1258 else
1259 bChangeInThisRun = TRUE;
1262 if( bChangeInThisRun && nNewPos )
1264 aNewPoly.SetSize( nNewPos );
1265 rPoly = aNewPoly;
1266 nNumNoChange = 0;
1268 else
1269 nNumNoChange++;
1271 nNumRuns++;
1275 // -----------------------------------------------------------------------
1277 void Polygon::Move( long nHorzMove, long nVertMove )
1279 DBG_CHKTHIS( Polygon, NULL );
1281 // Diese Abfrage sollte man fuer die DrawEngine durchfuehren
1282 if ( !nHorzMove && !nVertMove )
1283 return;
1285 ImplMakeUnique();
1287 // Punkte verschieben
1288 USHORT nCount = mpImplPolygon->mnPoints;
1289 for ( USHORT i = 0; i < nCount; i++ )
1291 Point* pPt = &(mpImplPolygon->mpPointAry[i]);
1292 pPt->X() += nHorzMove;
1293 pPt->Y() += nVertMove;
1297 // -----------------------------------------------------------------------
1299 void Polygon::Translate(const Point& rTrans)
1301 DBG_CHKTHIS( Polygon, NULL );
1302 ImplMakeUnique();
1304 for ( USHORT i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1305 mpImplPolygon->mpPointAry[ i ] += rTrans;
1308 // -----------------------------------------------------------------------
1310 void Polygon::Scale( double fScaleX, double fScaleY )
1312 DBG_CHKTHIS( Polygon, NULL );
1313 ImplMakeUnique();
1315 for ( USHORT i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1317 Point& rPnt = mpImplPolygon->mpPointAry[i];
1318 rPnt.X() = (long) ( fScaleX * rPnt.X() );
1319 rPnt.Y() = (long) ( fScaleY * rPnt.Y() );
1323 // -----------------------------------------------------------------------
1325 void Polygon::Rotate( const Point& rCenter, USHORT nAngle10 )
1327 DBG_CHKTHIS( Polygon, NULL );
1328 nAngle10 %= 3600;
1330 if( nAngle10 )
1332 const double fAngle = F_PI1800 * nAngle10;
1333 Rotate( rCenter, sin( fAngle ), cos( fAngle ) );
1337 // -----------------------------------------------------------------------
1339 void Polygon::Rotate( const Point& rCenter, double fSin, double fCos )
1341 DBG_CHKTHIS( Polygon, NULL );
1342 ImplMakeUnique();
1344 long nX, nY;
1345 long nCenterX = rCenter.X();
1346 long nCenterY = rCenter.Y();
1348 for( USHORT i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1350 Point& rPt = mpImplPolygon->mpPointAry[ i ];
1352 nX = rPt.X() - nCenterX;
1353 nY = rPt.Y() - nCenterY;
1354 rPt.X() = (long) FRound( fCos * nX + fSin * nY ) + nCenterX;
1355 rPt.Y() = -(long) FRound( fSin * nX - fCos * nY ) + nCenterY;
1359 // -----------------------------------------------------------------------
1361 void Polygon::SlantX( long nYRef, double fSin, double fCos )
1363 DBG_CHKTHIS( Polygon, NULL );
1364 ImplMakeUnique();
1366 for( USHORT i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1368 Point& rPnt = mpImplPolygon->mpPointAry[ i ];
1369 const long nDy = rPnt.Y() - nYRef;
1371 rPnt.X() += (long)( fSin * nDy );
1372 rPnt.Y() = nYRef + (long)( fCos * nDy );
1376 // -----------------------------------------------------------------------
1378 void Polygon::SlantY( long nXRef, double fSin, double fCos )
1380 DBG_CHKTHIS( Polygon, NULL );
1381 ImplMakeUnique();
1383 for( USHORT i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1385 Point& rPnt = mpImplPolygon->mpPointAry[ i ];
1386 const long nDx = rPnt.X() - nXRef;
1388 rPnt.X() = nXRef + (long)( fCos * nDx );
1389 rPnt.Y() -= (long)( fSin * nDx );
1393 // -----------------------------------------------------------------------
1395 void Polygon::Distort( const Rectangle& rRefRect, const Polygon& rDistortedRect )
1397 DBG_CHKTHIS( Polygon, NULL );
1398 ImplMakeUnique();
1400 long Xr, Wr, X1, X2, X3, X4;
1401 long Yr, Hr, Y1, Y2, Y3, Y4;
1402 double fTx, fTy, fUx, fUy;
1404 Xr = rRefRect.Left();
1405 Yr = rRefRect.Top();
1406 Wr = rRefRect.GetWidth();
1407 Hr = rRefRect.GetHeight();
1409 if( Wr && Hr )
1411 DBG_ASSERT( rDistortedRect.mpImplPolygon->mnPoints >= 4, "Distort rect too small!" );
1413 X1 = rDistortedRect[0].X();
1414 Y1 = rDistortedRect[0].Y();
1415 X2 = rDistortedRect[1].X();
1416 Y2 = rDistortedRect[1].Y();
1417 X3 = rDistortedRect[3].X();
1418 Y3 = rDistortedRect[3].Y();
1419 X4 = rDistortedRect[2].X();
1420 Y4 = rDistortedRect[2].Y();
1422 for( USHORT i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1424 Point& rPnt = mpImplPolygon->mpPointAry[ i ];
1426 fTx = (double)( rPnt.X() - Xr) / Wr;
1427 fTy = (double)( rPnt.Y() - Yr) / Hr;
1428 fUx = 1.0 - fTx;
1429 fUy = 1.0 - fTy;
1431 rPnt.X() = (long) ( fUy * (fUx * X1 + fTx * X2) + fTy * (fUx * X3 + fTx * X4) );
1432 rPnt.Y() = (long) ( fUx * (fUy * Y1 + fTy * Y3) + fTx * (fUy * Y2 + fTy * Y4) );
1437 // -----------------------------------------------------------------------
1439 class ImplPointFilter
1441 public:
1442 virtual void LastPoint() = 0;
1443 virtual void Input( const Point& rPoint ) = 0;
1446 class ImplPolygonPointFilter : public ImplPointFilter
1448 public:
1449 ImplPolygon* mpPoly; // Nicht loeschen, wird dem Polygon zugewiesen
1450 USHORT mnSize;
1452 ImplPolygonPointFilter( USHORT nDestSize ) :
1453 mnSize( 0 )
1455 mpPoly = new ImplPolygon( nDestSize );
1458 virtual void LastPoint();
1459 virtual void Input( const Point& rPoint );
1462 void ImplPolygonPointFilter::Input( const Point& rPoint )
1464 if ( !mnSize || (rPoint != mpPoly->mpPointAry[mnSize-1]) )
1466 mnSize++;
1467 if ( mnSize > mpPoly->mnPoints )
1468 mpPoly->ImplSetSize( mnSize );
1469 mpPoly->mpPointAry[mnSize-1] = rPoint;
1473 void ImplPolygonPointFilter::LastPoint()
1475 if ( mnSize < mpPoly->mnPoints )
1476 mpPoly->ImplSetSize( mnSize );
1479 class ImplEdgePointFilter : public ImplPointFilter
1481 Point maFirstPoint;
1482 Point maLastPoint;
1483 ImplPointFilter& mrNextFilter;
1484 const long mnLow;
1485 const long mnHigh;
1486 const int mnEdge;
1487 int mnLastOutside;
1488 BOOL mbFirst;
1490 public:
1491 ImplEdgePointFilter( int nEdge, long nLow, long nHigh,
1492 ImplPointFilter& rNextFilter ) :
1493 mrNextFilter( rNextFilter ),
1494 mnLow( nLow ),
1495 mnHigh( nHigh ),
1496 mnEdge( nEdge ),
1497 mbFirst( TRUE )
1501 Point EdgeSection( const Point& rPoint, int nEdge ) const;
1502 int VisibleSide( const Point& rPoint ) const;
1503 int IsPolygon() const
1504 { return maFirstPoint == maLastPoint; }
1506 virtual void Input( const Point& rPoint );
1507 virtual void LastPoint();
1510 inline int ImplEdgePointFilter::VisibleSide( const Point& rPoint ) const
1512 if ( mnEdge & EDGE_HORZ )
1514 return rPoint.X() < mnLow ? EDGE_LEFT :
1515 rPoint.X() > mnHigh ? EDGE_RIGHT : 0;
1517 else
1519 return rPoint.Y() < mnLow ? EDGE_TOP :
1520 rPoint.Y() > mnHigh ? EDGE_BOTTOM : 0;
1524 Point ImplEdgePointFilter::EdgeSection( const Point& rPoint, int nEdge ) const
1526 long lx = maLastPoint.X();
1527 long ly = maLastPoint.Y();
1528 long md = rPoint.X() - lx;
1529 long mn = rPoint.Y() - ly;
1530 long nNewX;
1531 long nNewY;
1533 if ( nEdge & EDGE_VERT )
1535 nNewY = (nEdge == EDGE_TOP) ? mnLow : mnHigh;
1536 long dy = nNewY - ly;
1537 if ( !md )
1538 nNewX = lx;
1539 else if ( (LONG_MAX / Abs(md)) >= Abs(dy) )
1540 nNewX = (dy * md) / mn + lx;
1541 else
1543 BigInt ady = dy;
1544 ady *= md;
1545 if( ady.IsNeg() )
1546 if( mn < 0 )
1547 ady += mn/2;
1548 else
1549 ady -= (mn-1)/2;
1550 else
1551 if( mn < 0 )
1552 ady -= (mn+1)/2;
1553 else
1554 ady += mn/2;
1555 ady /= mn;
1556 nNewX = (long)ady + lx;
1559 else
1561 nNewX = (nEdge == EDGE_LEFT) ? mnLow : mnHigh;
1562 long dx = nNewX - lx;
1563 if ( !mn )
1564 nNewY = ly;
1565 else if ( (LONG_MAX / Abs(mn)) >= Abs(dx) )
1566 nNewY = (dx * mn) / md + ly;
1567 else
1569 BigInt adx = dx;
1570 adx *= mn;
1571 if( adx.IsNeg() )
1572 if( md < 0 )
1573 adx += md/2;
1574 else
1575 adx -= (md-1)/2;
1576 else
1577 if( md < 0 )
1578 adx -= (md+1)/2;
1579 else
1580 adx += md/2;
1581 adx /= md;
1582 nNewY = (long)adx + ly;
1586 return Point( nNewX, nNewY );
1589 void ImplEdgePointFilter::Input( const Point& rPoint )
1591 int nOutside = VisibleSide( rPoint );
1593 if ( mbFirst )
1595 maFirstPoint = rPoint;
1596 mbFirst = FALSE;
1597 if ( !nOutside )
1598 mrNextFilter.Input( rPoint );
1600 else if ( rPoint == maLastPoint )
1601 return;
1602 else if ( !nOutside )
1604 if ( mnLastOutside )
1605 mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1606 mrNextFilter.Input( rPoint );
1608 else if ( !mnLastOutside )
1609 mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1610 else if ( nOutside != mnLastOutside )
1612 mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1613 mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1616 maLastPoint = rPoint;
1617 mnLastOutside = nOutside;
1620 void ImplEdgePointFilter::LastPoint()
1622 if ( !mbFirst )
1624 int nOutside = VisibleSide( maFirstPoint );
1626 if ( nOutside != mnLastOutside )
1627 Input( maFirstPoint );
1628 mrNextFilter.LastPoint();
1632 // -----------------------------------------------------------------------
1634 void Polygon::Clip( const Rectangle& rRect, BOOL bPolygon )
1636 // #105251# Justify rect befor edge filtering
1637 Rectangle aJustifiedRect( rRect );
1638 aJustifiedRect.Justify();
1640 USHORT nSourceSize = mpImplPolygon->mnPoints;
1641 ImplPolygonPointFilter aPolygon( nSourceSize );
1642 ImplEdgePointFilter aHorzFilter( EDGE_HORZ, aJustifiedRect.Left(), aJustifiedRect.Right(),
1643 aPolygon );
1644 ImplEdgePointFilter aVertFilter( EDGE_VERT, aJustifiedRect.Top(), aJustifiedRect.Bottom(),
1645 aHorzFilter );
1647 for ( USHORT i = 0; i < nSourceSize; i++ )
1648 aVertFilter.Input( mpImplPolygon->mpPointAry[i] );
1649 if ( bPolygon || aVertFilter.IsPolygon() )
1650 aVertFilter.LastPoint();
1651 else
1652 aPolygon.LastPoint();
1654 // Alte ImpPolygon-Daten loeschen und die vom ImpPolygonPointFilter
1655 // zuweisen
1656 if ( mpImplPolygon->mnRefCount )
1658 if ( mpImplPolygon->mnRefCount > 1 )
1659 mpImplPolygon->mnRefCount--;
1660 else
1661 delete mpImplPolygon;
1663 mpImplPolygon = aPolygon.mpPoly;
1666 // -----------------------------------------------------------------------
1668 Rectangle Polygon::GetBoundRect() const
1670 DBG_CHKTHIS( Polygon, NULL );
1671 DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetBoundRect could fail with beziers!" );
1673 USHORT nCount = mpImplPolygon->mnPoints;
1674 if( ! nCount )
1675 return Rectangle();
1677 long nXMin, nXMax, nYMin, nYMax;
1679 const Point* pPt = &(mpImplPolygon->mpPointAry[0]);
1680 nXMin = nXMax = pPt->X();
1681 nYMin = nYMax = pPt->Y();
1683 for ( USHORT i = 0; i < nCount; i++ )
1685 pPt = &(mpImplPolygon->mpPointAry[i]);
1687 if ( pPt->X() < nXMin )
1688 nXMin = pPt->X();
1689 if ( pPt->X() > nXMax )
1690 nXMax = pPt->X();
1691 if ( pPt->Y() < nYMin )
1692 nYMin = pPt->Y();
1693 if ( pPt->Y() > nYMax )
1694 nYMax = pPt->Y();
1697 return Rectangle( nXMin, nYMin, nXMax, nYMax );
1700 // -----------------------------------------------------------------------
1702 double Polygon::GetArea() const
1704 const double fArea = GetSignedArea();
1705 return( ( fArea < 0.0 ) ? -fArea : fArea );
1708 // -----------------------------------------------------------------------
1710 double Polygon::GetSignedArea() const
1712 DBG_CHKTHIS( Polygon, NULL );
1713 DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetArea could fail with beziers!" );
1715 double fArea = 0.0;
1717 if( mpImplPolygon->mnPoints > 2 )
1719 const USHORT nCount1 = mpImplPolygon->mnPoints - 1;
1721 for( USHORT i = 0; i < nCount1; )
1723 const Point& rPt = mpImplPolygon->mpPointAry[ i ];
1724 const Point& rPt1 = mpImplPolygon->mpPointAry[ ++i ];
1725 fArea += ( rPt.X() - rPt1.X() ) * ( rPt.Y() + rPt1.Y() );
1728 const Point& rPt = mpImplPolygon->mpPointAry[ nCount1 ];
1729 const Point& rPt0 = mpImplPolygon->mpPointAry[ 0 ];
1730 fArea += ( rPt.X() - rPt0.X() ) * ( rPt.Y() + rPt0.Y() );
1733 return fArea;
1736 // -----------------------------------------------------------------------
1738 BOOL Polygon::IsInside( const Point& rPoint ) const
1740 DBG_CHKTHIS( Polygon, NULL );
1741 DBG_ASSERT( !mpImplPolygon->mpFlagAry, "IsInside could fail with beziers!" );
1743 const Rectangle aBound( GetBoundRect() );
1744 const Line aLine( rPoint, Point( aBound.Right() + 100L, rPoint.Y() ) );
1745 USHORT nCount = mpImplPolygon->mnPoints;
1746 USHORT nPCounter = 0;
1748 if ( ( nCount > 2 ) && aBound.IsInside( rPoint ) )
1750 Point aPt1( mpImplPolygon->mpPointAry[ 0 ] );
1751 Point aIntersection;
1752 Point aLastIntersection;
1754 while ( ( aPt1 == mpImplPolygon->mpPointAry[ nCount - 1 ] ) && ( nCount > 3 ) )
1755 nCount--;
1757 for ( USHORT i = 1; i <= nCount; i++ )
1759 const Point& rPt2 = mpImplPolygon->mpPointAry[ ( i < nCount ) ? i : 0 ];
1761 if ( aLine.Intersection( Line( aPt1, rPt2 ), aIntersection ) )
1763 // Hiermit verhindern wir das Einfuegen von
1764 // doppelten Intersections, die gleich hintereinander folgen
1765 if ( nPCounter )
1767 if ( aIntersection != aLastIntersection )
1769 aLastIntersection = aIntersection;
1770 nPCounter++;
1773 else
1775 aLastIntersection = aIntersection;
1776 nPCounter++;
1780 aPt1 = rPt2;
1784 // innerhalb, wenn die Anzahl der Schnittpunkte ungerade ist
1785 return ( ( nPCounter & 1 ) == 1 );
1788 // -----------------------------------------------------------------------
1790 BOOL Polygon::IsRightOrientated() const
1792 DBG_CHKTHIS( Polygon, NULL );
1793 return GetSignedArea() >= 0.0;
1796 // -----------------------------------------------------------------------
1798 void Polygon::Insert( USHORT nPos, const Point& rPt, PolyFlags eFlags )
1800 DBG_CHKTHIS( Polygon, NULL );
1801 ImplMakeUnique();
1803 if( nPos >= mpImplPolygon->mnPoints )
1804 nPos = mpImplPolygon->mnPoints;
1806 mpImplPolygon->ImplSplit( nPos, 1 );
1807 mpImplPolygon->mpPointAry[ nPos ] = rPt;
1809 if( POLY_NORMAL != eFlags )
1811 mpImplPolygon->ImplCreateFlagArray();
1812 mpImplPolygon->mpFlagAry[ nPos ] = (BYTE) eFlags;
1816 // -----------------------------------------------------------------------
1818 void Polygon::Insert( USHORT nPos, const Polygon& rPoly )
1820 DBG_CHKTHIS( Polygon, NULL );
1821 const USHORT nInsertCount = rPoly.mpImplPolygon->mnPoints;
1823 if( nInsertCount )
1825 ImplMakeUnique();
1827 if( nPos >= mpImplPolygon->mnPoints )
1828 nPos = mpImplPolygon->mnPoints;
1830 if( rPoly.mpImplPolygon->mpFlagAry )
1831 mpImplPolygon->ImplCreateFlagArray();
1833 mpImplPolygon->ImplSplit( nPos, nInsertCount, rPoly.mpImplPolygon );
1837 // -----------------------------------------------------------------------
1839 void Polygon::Remove( USHORT nPos, USHORT nCount )
1841 DBG_CHKTHIS( Polygon, NULL );
1842 if( nCount && ( nPos < mpImplPolygon->mnPoints ) )
1844 ImplMakeUnique();
1845 mpImplPolygon->ImplRemove( nPos, nCount );
1849 // -----------------------------------------------------------------------
1851 Point& Polygon::operator[]( USHORT nPos )
1853 DBG_CHKTHIS( Polygon, NULL );
1854 DBG_ASSERT( nPos < mpImplPolygon->mnPoints, "Polygon::[]: nPos >= nPoints" );
1856 ImplMakeUnique();
1857 return mpImplPolygon->mpPointAry[nPos];
1860 // -----------------------------------------------------------------------
1862 Polygon& Polygon::operator=( const Polygon& rPoly )
1864 DBG_CHKTHIS( Polygon, NULL );
1865 DBG_CHKOBJ( &rPoly, Polygon, NULL );
1866 DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
1868 // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
1869 // RefCount == 0 fuer statische Objekte
1870 if ( rPoly.mpImplPolygon->mnRefCount )
1871 rPoly.mpImplPolygon->mnRefCount++;
1873 // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
1874 // die letzte Referenz ist, sonst Referenzcounter decrementieren
1875 if ( mpImplPolygon->mnRefCount )
1877 if ( mpImplPolygon->mnRefCount > 1 )
1878 mpImplPolygon->mnRefCount--;
1879 else
1880 delete mpImplPolygon;
1883 mpImplPolygon = rPoly.mpImplPolygon;
1884 return *this;
1887 // -----------------------------------------------------------------------
1889 BOOL Polygon::operator==( const Polygon& rPoly ) const
1891 DBG_CHKTHIS( Polygon, NULL );
1892 DBG_CHKOBJ( &rPoly, Polygon, NULL );
1894 if ( (rPoly.mpImplPolygon == mpImplPolygon) )
1895 return TRUE;
1896 else
1897 return FALSE;
1900 // -----------------------------------------------------------------------
1902 sal_Bool Polygon::IsEqual( const Polygon& rPoly ) const
1904 sal_Bool bIsEqual = sal_True;;
1905 sal_uInt16 i;
1906 if ( GetSize() != rPoly.GetSize() )
1907 bIsEqual = sal_False;
1908 else
1910 for ( i = 0; i < GetSize(); i++ )
1912 if ( ( GetPoint( i ) != rPoly.GetPoint( i ) ) ||
1913 ( GetFlags( i ) != rPoly.GetFlags( i ) ) )
1915 bIsEqual = sal_False;
1916 break;
1920 return bIsEqual;
1923 // -----------------------------------------------------------------------
1925 SvStream& operator>>( SvStream& rIStream, Polygon& rPoly )
1927 DBG_CHKOBJ( &rPoly, Polygon, NULL );
1928 DBG_ASSERTWARNING( rIStream.GetVersion(), "Polygon::>> - Solar-Version not set on rIStream" );
1930 USHORT i;
1931 USHORT nStart;
1932 USHORT nCurPoints;
1933 USHORT nPoints;
1934 unsigned char bShort;
1935 short nShortX;
1936 short nShortY;
1937 long nLongX;
1938 long nLongY;
1940 // Anzahl der Punkte einlesen und Array erzeugen
1941 rIStream >> nPoints;
1942 if ( rPoly.mpImplPolygon->mnRefCount != 1 )
1944 if ( rPoly.mpImplPolygon->mnRefCount )
1945 rPoly.mpImplPolygon->mnRefCount--;
1946 rPoly.mpImplPolygon = new ImplPolygon( nPoints );
1948 else
1949 rPoly.mpImplPolygon->ImplSetSize( nPoints, FALSE );
1951 // Je nach CompressMode das Polygon einlesen
1952 if ( rIStream.GetCompressMode() == COMPRESSMODE_FULL )
1954 i = 0;
1955 while ( i < nPoints )
1957 rIStream >> bShort >> nCurPoints;
1959 if ( bShort )
1961 for ( nStart = i; i < nStart+nCurPoints; i++ )
1963 rIStream >> nShortX >> nShortY;
1964 rPoly.mpImplPolygon->mpPointAry[i].X() = nShortX;
1965 rPoly.mpImplPolygon->mpPointAry[i].Y() = nShortY;
1968 else
1970 for ( nStart = i; i < nStart+nCurPoints; i++ )
1972 rIStream >> nLongX >> nLongY;
1973 rPoly.mpImplPolygon->mpPointAry[i].X() = nLongX;
1974 rPoly.mpImplPolygon->mpPointAry[i].Y() = nLongY;
1979 else
1981 // Feststellen, ob ueber die Operatoren geschrieben werden muss
1982 #if (SAL_TYPES_SIZEOFLONG) != 4
1983 if ( 1 )
1984 #else
1985 #ifdef OSL_BIGENDIAN
1986 if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
1987 #else
1988 if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
1989 #endif
1990 #endif
1992 for( i = 0; i < nPoints; i++ )
1994 rIStream >> rPoly.mpImplPolygon->mpPointAry[i].X()
1995 >> rPoly.mpImplPolygon->mpPointAry[i].Y();
1998 else
1999 rIStream.Read( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
2002 return rIStream;
2005 // -----------------------------------------------------------------------
2007 SvStream& operator<<( SvStream& rOStream, const Polygon& rPoly )
2009 DBG_CHKOBJ( &rPoly, Polygon, NULL );
2010 DBG_ASSERTWARNING( rOStream.GetVersion(), "Polygon::<< - Solar-Version not set on rOStream" );
2012 unsigned char bShort;
2013 unsigned char bCurShort;
2014 USHORT nStart;
2015 USHORT i;
2016 USHORT nPoints = rPoly.GetSize();
2018 // Anzahl der Punkte rausschreiben
2019 rOStream << nPoints;
2021 // Je nach CompressMode das Polygon rausschreiben
2022 if ( rOStream.GetCompressMode() == COMPRESSMODE_FULL )
2024 i = 0;
2025 while ( i < nPoints )
2027 nStart = i;
2029 // Feststellen, welcher Typ geschrieben werden soll
2030 if ( ((rPoly.mpImplPolygon->mpPointAry[nStart].X() >= SHRT_MIN) &&
2031 (rPoly.mpImplPolygon->mpPointAry[nStart].X() <= SHRT_MAX)) &&
2032 ((rPoly.mpImplPolygon->mpPointAry[nStart].Y() >= SHRT_MIN) &&
2033 (rPoly.mpImplPolygon->mpPointAry[nStart].Y() <= SHRT_MAX)) )
2034 bShort = TRUE;
2035 else
2036 bShort = FALSE;
2037 while ( i < nPoints )
2039 // Feststellen, welcher Typ geschrieben werden soll
2040 if ( ((rPoly.mpImplPolygon->mpPointAry[nStart].X() >= SHRT_MIN) &&
2041 (rPoly.mpImplPolygon->mpPointAry[nStart].X() <= SHRT_MAX)) &&
2042 ((rPoly.mpImplPolygon->mpPointAry[nStart].Y() >= SHRT_MIN) &&
2043 (rPoly.mpImplPolygon->mpPointAry[nStart].Y() <= SHRT_MAX)) )
2044 bCurShort = TRUE;
2045 else
2046 bCurShort = FALSE;
2048 // Wenn sich die Werte in einen anderen Bereich begeben,
2049 // muessen wir neu rausschreiben
2050 if ( bCurShort != bShort )
2052 bShort = bCurShort;
2053 break;
2056 i++;
2059 rOStream << bShort << (USHORT)(i-nStart);
2061 if ( bShort )
2063 for( ; nStart < i; nStart++ )
2065 rOStream << (short)rPoly.mpImplPolygon->mpPointAry[nStart].X()
2066 << (short)rPoly.mpImplPolygon->mpPointAry[nStart].Y();
2069 else
2071 for( ; nStart < i; nStart++ )
2073 rOStream << rPoly.mpImplPolygon->mpPointAry[nStart].X()
2074 << rPoly.mpImplPolygon->mpPointAry[nStart].Y();
2079 else
2081 // Feststellen, ob ueber die Operatoren geschrieben werden muss
2082 #if (SAL_TYPES_SIZEOFLONG) != 4
2083 if ( 1 )
2084 #else
2085 #ifdef OSL_BIGENDIAN
2086 if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
2087 #else
2088 if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
2089 #endif
2090 #endif
2092 for( i = 0; i < nPoints; i++ )
2094 rOStream << rPoly.mpImplPolygon->mpPointAry[i].X()
2095 << rPoly.mpImplPolygon->mpPointAry[i].Y();
2098 else
2100 if ( nPoints )
2101 rOStream.Write( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
2105 return rOStream;
2108 // -----------------------------------------------------------------------
2110 void Polygon::ImplRead( SvStream& rIStream )
2112 sal_uInt8 bHasPolyFlags;
2114 rIStream >> *this
2115 >> bHasPolyFlags;
2117 if ( bHasPolyFlags )
2119 mpImplPolygon->mpFlagAry = new sal_uInt8[ mpImplPolygon->mnPoints ];
2120 rIStream.Read( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
2124 // -----------------------------------------------------------------------
2126 void Polygon::Read( SvStream& rIStream )
2128 VersionCompat aCompat( rIStream, STREAM_READ );
2130 ImplRead( rIStream );
2133 // -----------------------------------------------------------------------
2135 void Polygon::ImplWrite( SvStream& rOStream ) const
2137 sal_uInt8 bHasPolyFlags = mpImplPolygon->mpFlagAry != NULL;
2138 rOStream << *this
2139 << bHasPolyFlags;
2141 if ( bHasPolyFlags )
2142 rOStream.Write( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
2145 // -----------------------------------------------------------------------
2147 void Polygon::Write( SvStream& rOStream ) const
2149 VersionCompat aCompat( rOStream, STREAM_WRITE, 1 );
2151 ImplWrite( rOStream );
2154 // -----------------------------------------------------------------------
2155 // #i74631# numerical correction method for B2DPolygon
2156 void impCorrectContinuity(basegfx::B2DPolygon& roPolygon, sal_uInt32 nIndex, BYTE nCFlag)
2158 const sal_uInt32 nPointCount(roPolygon.count());
2159 OSL_ENSURE(nIndex < nPointCount, "impCorrectContinuity: index access out of range (!)");
2161 if(nIndex < nPointCount && (POLY_SMOOTH == nCFlag || POLY_SYMMTR == nCFlag))
2163 if(roPolygon.isPrevControlPointUsed(nIndex) && roPolygon.isNextControlPointUsed(nIndex))
2165 const basegfx::B2DPoint aPoint(roPolygon.getB2DPoint(nIndex));
2167 if(POLY_SMOOTH == nCFlag)
2169 // C1: apply inverse direction of prev to next, keep length of next
2170 const basegfx::B2DVector aOriginalNext(roPolygon.getNextControlPoint(nIndex) - aPoint);
2171 basegfx::B2DVector aNewNext(aPoint - roPolygon.getPrevControlPoint(nIndex));
2173 aNewNext.setLength(aOriginalNext.getLength());
2174 roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + aNewNext));
2176 else // POLY_SYMMTR
2178 // C2: apply inverse control point to next
2179 roPolygon.setNextControlPoint(nIndex, (2.0 * aPoint) - roPolygon.getPrevControlPoint(nIndex));
2185 // -----------------------------------------------------------------------
2186 // convert to basegfx::B2DPolygon and return
2187 basegfx::B2DPolygon Polygon::getB2DPolygon() const
2189 basegfx::B2DPolygon aRetval;
2190 const sal_uInt16 nCount(mpImplPolygon->mnPoints);
2192 if(nCount)
2194 if(mpImplPolygon->mpFlagAry)
2196 // handling for curves. Add start point
2197 const Point aStartPoint(mpImplPolygon->mpPointAry[0]);
2198 BYTE nPointFlag(mpImplPolygon->mpFlagAry[0]);
2199 aRetval.append(basegfx::B2DPoint(aStartPoint.X(), aStartPoint.Y()));
2200 Point aControlA, aControlB;
2202 for(sal_uInt16 a(1); a < nCount;)
2204 bool bControlA(false);
2205 bool bControlB(false);
2207 if(POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
2209 aControlA = mpImplPolygon->mpPointAry[a++];
2210 bControlA = true;
2213 if(a < nCount && POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
2215 aControlB = mpImplPolygon->mpPointAry[a++];
2216 bControlB = true;
2219 // assert invalid polygons
2220 OSL_ENSURE(bControlA == bControlB, "Polygon::getB2DPolygon: Invalid source polygon (!)");
2222 if(a < nCount)
2224 const Point aEndPoint(mpImplPolygon->mpPointAry[a]);
2226 if(bControlA)
2228 // bezier edge, add
2229 aRetval.appendBezierSegment(
2230 basegfx::B2DPoint(aControlA.X(), aControlA.Y()),
2231 basegfx::B2DPoint(aControlB.X(), aControlB.Y()),
2232 basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
2234 impCorrectContinuity(aRetval, aRetval.count() - 2, nPointFlag);
2236 else
2238 // no bezier edge, add end point
2239 aRetval.append(basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
2242 nPointFlag = mpImplPolygon->mpFlagAry[a++];
2246 // if exist, remove double first/last points, set closed and correct control points
2247 basegfx::tools::checkClosed(aRetval);
2249 if(aRetval.isClosed())
2251 // closeWithGeometryChange did really close, so last point(s) were removed.
2252 // Correct the continuity in the changed point
2253 impCorrectContinuity(aRetval, 0, mpImplPolygon->mpFlagAry[0]);
2256 else
2258 // extra handling for non-curves (most-used case) for speedup
2259 for(sal_uInt16 a(0); a < nCount; a++)
2261 // get point and add
2262 const Point aPoint(mpImplPolygon->mpPointAry[a]);
2263 aRetval.append(basegfx::B2DPoint(aPoint.X(), aPoint.Y()));
2266 // set closed flag
2267 basegfx::tools::checkClosed(aRetval);
2271 return aRetval;
2274 // -----------------------------------------------------------------------
2275 // constructor to convert from basegfx::B2DPolygon
2276 // #i76891# Needed to change from adding all control points (even for unused
2277 // edges) and creating a fixed-size Polygon in the first run to creating the
2278 // minimal Polygon. This requires a temporary Point- and Flag-Array for curves
2279 // and a memcopy at ImplPolygon creation, but contains no zero-controlpoints
2280 // for straight edges.
2281 Polygon::Polygon(const basegfx::B2DPolygon& rPolygon)
2282 : mpImplPolygon(0)
2284 DBG_CTOR( Polygon, NULL );
2286 const bool bCurve(rPolygon.areControlPointsUsed());
2287 const bool bClosed(rPolygon.isClosed());
2288 sal_uInt32 nB2DLocalCount(rPolygon.count());
2290 if(bCurve)
2292 // #127979# Reduce source point count hard to the limit of the tools Polygon
2293 if(nB2DLocalCount > ((0x0000ffff / 3L) - 1L))
2295 DBG_ERROR("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
2296 nB2DLocalCount = ((0x0000ffff / 3L) - 1L);
2299 // calculate target point count
2300 const sal_uInt32 nLoopCount(bClosed ? nB2DLocalCount : (nB2DLocalCount ? nB2DLocalCount - 1L : 0L ));
2302 if(nLoopCount)
2304 // calculate maximum array size and allocate; prepare insert index
2305 const sal_uInt32 nMaxTargetCount((nLoopCount * 3) + 1);
2306 mpImplPolygon = new ImplPolygon(static_cast< sal_uInt16 >(nMaxTargetCount), true);
2308 // prepare insert index and current point
2309 sal_uInt32 nArrayInsert(0);
2310 basegfx::B2DCubicBezier aBezier;
2311 aBezier.setStartPoint(rPolygon.getB2DPoint(0));
2313 for(sal_uInt32 a(0L); a < nLoopCount; a++)
2315 // add current point (always) and remember StartPointIndex for evtl. later corrections
2316 const Point aStartPoint(FRound(aBezier.getStartPoint().getX()), FRound(aBezier.getStartPoint().getY()));
2317 const sal_uInt32 nStartPointIndex(nArrayInsert);
2318 mpImplPolygon->mpPointAry[nStartPointIndex] = aStartPoint;
2319 mpImplPolygon->mpFlagAry[nStartPointIndex] = (BYTE)POLY_NORMAL;
2320 nArrayInsert++;
2322 // prepare next segment
2323 const sal_uInt32 nNextIndex((a + 1) % nB2DLocalCount);
2324 aBezier.setEndPoint(rPolygon.getB2DPoint(nNextIndex));
2325 aBezier.setControlPointA(rPolygon.getNextControlPoint(a));
2326 aBezier.setControlPointB(rPolygon.getPrevControlPoint(nNextIndex));
2328 if(aBezier.isBezier())
2330 // if one is used, add always two control points due to the old schema
2331 mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointA().getX()), FRound(aBezier.getControlPointA().getY()));
2332 mpImplPolygon->mpFlagAry[nArrayInsert] = (BYTE)POLY_CONTROL;
2333 nArrayInsert++;
2335 mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointB().getX()), FRound(aBezier.getControlPointB().getY()));
2336 mpImplPolygon->mpFlagAry[nArrayInsert] = (BYTE)POLY_CONTROL;
2337 nArrayInsert++;
2340 // test continuity with previous control point to set flag value
2341 if(aBezier.getControlPointA() != aBezier.getStartPoint() && (bClosed || a))
2343 const basegfx::B2VectorContinuity eCont(rPolygon.getContinuityInPoint(a));
2345 if(basegfx::CONTINUITY_C1 == eCont)
2347 mpImplPolygon->mpFlagAry[nStartPointIndex] = (BYTE)POLY_SMOOTH;
2349 else if(basegfx::CONTINUITY_C2 == eCont)
2351 mpImplPolygon->mpFlagAry[nStartPointIndex] = (BYTE)POLY_SYMMTR;
2355 // prepare next polygon step
2356 aBezier.setStartPoint(aBezier.getEndPoint());
2359 if(bClosed)
2361 // add first point again as closing point due to old definition
2362 mpImplPolygon->mpPointAry[nArrayInsert] = mpImplPolygon->mpPointAry[0];
2363 mpImplPolygon->mpFlagAry[nArrayInsert] = (BYTE)POLY_NORMAL;
2364 nArrayInsert++;
2366 else
2368 // add last point as closing point
2369 const basegfx::B2DPoint aClosingPoint(rPolygon.getB2DPoint(nB2DLocalCount - 1L));
2370 const Point aEnd(FRound(aClosingPoint.getX()), FRound(aClosingPoint.getY()));
2371 mpImplPolygon->mpPointAry[nArrayInsert] = aEnd;
2372 mpImplPolygon->mpFlagAry[nArrayInsert] = (BYTE)POLY_NORMAL;
2373 nArrayInsert++;
2376 DBG_ASSERT(nArrayInsert <= nMaxTargetCount, "Polygon::Polygon from basegfx::B2DPolygon: wrong max point count estimation (!)");
2378 if(nArrayInsert != nMaxTargetCount)
2380 mpImplPolygon->ImplSetSize(static_cast< sal_uInt16 >(nArrayInsert), true);
2384 else
2386 // #127979# Reduce source point count hard to the limit of the tools Polygon
2387 if(nB2DLocalCount > (0x0000ffff - 1L))
2389 DBG_ERROR("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
2390 nB2DLocalCount = (0x0000ffff - 1L);
2393 if(nB2DLocalCount)
2395 // point list creation
2396 const sal_uInt32 nTargetCount(nB2DLocalCount + (bClosed ? 1L : 0L));
2397 mpImplPolygon = new ImplPolygon( static_cast< sal_uInt16 >(nTargetCount) );
2398 sal_uInt16 nIndex(0);
2400 for(sal_uInt32 a(0L); a < nB2DLocalCount; a++)
2402 basegfx::B2DPoint aB2DPoint(rPolygon.getB2DPoint(a));
2403 Point aPoint(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY()));
2404 mpImplPolygon->mpPointAry[nIndex++] = aPoint;
2407 if(bClosed)
2409 // add first point as closing point
2410 mpImplPolygon->mpPointAry[nIndex] = mpImplPolygon->mpPointAry[0];
2415 if(!mpImplPolygon)
2417 // no content yet, create empty polygon
2418 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
2422 // eof