1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: poly.cxx,v $
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"
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>
41 #include <tools/line.hxx>
43 #include <tools/vector2d.hxx>
46 #include <tools/poly.hxx>
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>
62 // =======================================================================
66 // -----------------------------------------------------------------------
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
=
84 // =======================================================================
86 ImplPolygon::ImplPolygon( USHORT nInitSize
, BOOL bFlags
)
90 mpPointAry
= (Point
*)new char[(ULONG
)nInitSize
*sizeof(Point
)];
91 memset( mpPointAry
, 0, (ULONG
)nInitSize
*sizeof(Point
) );
98 mpFlagAry
= new BYTE
[ nInitSize
];
99 memset( mpPointAry
, 0, nInitSize
);
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
);
132 mnPoints
= rImpPoly
.mnPoints
;
135 // -----------------------------------------------------------------------
137 ImplPolygon::ImplPolygon( USHORT nInitSize
, const Point
* pInitAry
, const BYTE
* pInitFlags
)
141 mpPointAry
= (Point
*)new char[(ULONG
)nInitSize
*sizeof(Point
)];
142 memcpy( mpPointAry
, pInitAry
, (ULONG
)nInitSize
*sizeof( Point
) );
146 mpFlagAry
= new BYTE
[ nInitSize
];
147 memcpy( mpFlagAry
, pInitFlags
, nInitSize
);
159 mnPoints
= nInitSize
;
162 // -----------------------------------------------------------------------
164 ImplPolygon::~ImplPolygon()
168 delete[] (char*) mpPointAry
;
175 // -----------------------------------------------------------------------
177 void ImplPolygon::ImplSetSize( USHORT nNewSize
, BOOL bResize
)
179 if( mnPoints
== nNewSize
)
186 pNewAry
= (Point
*)new char[(ULONG
)nNewSize
*sizeof(Point
)];
190 // Alte Punkte kopieren
191 if ( mnPoints
< nNewSize
)
193 // Neue Punkte mit 0 initialisieren
194 memset( pNewAry
+mnPoints
, 0, (ULONG
)(nNewSize
-mnPoints
)*sizeof(Point
) );
196 memcpy( pNewAry
, mpPointAry
, mnPoints
*sizeof(Point
) );
201 memcpy( pNewAry
, mpPointAry
, (ULONG
)nNewSize
*sizeof(Point
) );
209 delete[] (char*) mpPointAry
;
211 // ggf. FlagArray beruecksichtigen
218 pNewFlagAry
= new BYTE
[ nNewSize
];
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
);
230 memcpy( pNewFlagAry
, mpFlagAry
, nNewSize
);
237 mpFlagAry
= pNewFlagAry
;
240 mpPointAry
= pNewAry
;
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
)
255 ImplSetSize( nNewSize
, TRUE
);
259 memcpy( mpPointAry
+ nPos
, pInitPoly
->mpPointAry
, nSpaceSize
);
261 if( pInitPoly
->mpFlagAry
)
262 memcpy( mpFlagAry
+ nPos
, pInitPoly
->mpFlagAry
, nSpace
);
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
) );
276 memcpy( pNewAry
+ nPos
, pInitPoly
->mpPointAry
, nSpaceSize
);
278 memset( pNewAry
+ nPos
, 0, nSpaceSize
);
280 memcpy( pNewAry
+ nSecPos
, mpPointAry
+ nPos
, nRest
* sizeof( Point
) );
281 delete[] (char*) mpPointAry
;
283 // ggf. FlagArray beruecksichtigen
286 BYTE
* pNewFlagAry
= new BYTE
[ nNewSize
];
288 memcpy( pNewFlagAry
, mpFlagAry
, nPos
);
290 if( pInitPoly
&& pInitPoly
->mpFlagAry
)
291 memcpy( pNewFlagAry
+ nPos
, pInitPoly
->mpFlagAry
, nSpace
);
293 memset( pNewFlagAry
+ nPos
, 0, nSpace
);
295 memcpy( pNewFlagAry
+ nSecPos
, mpFlagAry
+ nPos
, nRest
);
297 mpFlagAry
= pNewFlagAry
;
300 mpPointAry
= pNewAry
;
305 // -----------------------------------------------------------------------
307 void ImplPolygon::ImplRemove( USHORT nPos
, USHORT nCount
)
309 const USHORT nRemoveCount
= Min( (USHORT
) ( mnPoints
- nPos
), (USHORT
) nCount
);
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
327 BYTE
* pNewFlagAry
= new BYTE
[ nNewSize
];
329 memcpy( pNewFlagAry
, mpFlagAry
, nPos
);
330 memcpy( pNewFlagAry
+ nPos
, mpFlagAry
+ nSecPos
, nRest
);
332 mpFlagAry
= pNewFlagAry
;
335 mpPointAry
= pNewAry
;
340 // -----------------------------------------------------------------------
342 void ImplPolygon::ImplCreateFlagArray()
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 // -----------------------------------------------------------------------
376 DBG_CTOR( Polygon
, NULL
);
377 mpImplPolygon
= (ImplPolygon
*)(&aStaticImplPolygon
);
380 // -----------------------------------------------------------------------
382 Polygon::Polygon( USHORT nSize
)
384 DBG_CTOR( Polygon
, NULL
);
387 mpImplPolygon
= new ImplPolygon( nSize
);
389 mpImplPolygon
= (ImplPolygon
*)(&aStaticImplPolygon
);
392 // -----------------------------------------------------------------------
394 Polygon::Polygon( USHORT nPoints
, const Point
* pPtAry
, const BYTE
* pFlagAry
)
396 DBG_CTOR( Polygon
, NULL
);
399 mpImplPolygon
= new ImplPolygon( nPoints
, pPtAry
, pFlagAry
);
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
);
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
);
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();
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 ];
493 // -----------------------------------------------------------------------
495 Polygon::Polygon( const Point
& rCenter
, long nRadX
, long nRadY
, USHORT nPoints
)
497 DBG_CTOR( Polygon
, NULL
);
501 // Default berechnen (abhaengig von Groesse)
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 )
513 // Anzahl der Punkte auf durch 4 teilbare Zahl aufrunden
514 mpImplPolygon
= new ImplPolygon( nPoints
= (nPoints
+ 3) & ~3 );
518 USHORT nPoints2
= nPoints
>> 1;
519 USHORT nPoints4
= nPoints
>> 2;
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();
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();
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 )
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
;
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
) );
598 mpImplPolygon
= new ImplPolygon( nPoints
+ 2 );
599 mpImplPolygon
->mpPointAry
[ 0 ] = aCenter2
;
600 mpImplPolygon
->mpPointAry
[ nEnd
] = aCenter2
;
604 mpImplPolygon
= new ImplPolygon( ( POLY_CHORD
== eStyle
) ? ( nPoints
+ 1 ) : 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 ];
621 mpImplPolygon
= (ImplPolygon
*) &aStaticImplPolygon
;
624 // -----------------------------------------------------------------------
626 Polygon::Polygon( const Point
& rBezPt1
, const Point
& rCtrlPt1
,
627 const Point
& rBezPt2
, const Point
& rCtrlPt2
,
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 // -----------------------------------------------------------------------
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
--;
674 delete mpImplPolygon
;
678 // -----------------------------------------------------------------------
680 Point
* Polygon::ImplGetPointAry()
682 DBG_CHKTHIS( Polygon
, NULL
);
685 return (Point
*)mpImplPolygon
->mpPointAry
;
688 // -----------------------------------------------------------------------
690 BYTE
* Polygon::ImplGetFlagAry()
692 DBG_CHKTHIS( Polygon
, NULL
);
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" );
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
) )
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
] :
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() ) )
821 // -----------------------------------------------------------------------
823 void Polygon::SetSize( USHORT nNewSize
)
825 DBG_CHKTHIS( Polygon
, NULL
);
827 if( nNewSize
!= mpImplPolygon
->mnPoints
)
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
--;
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
) )
900 const Point
& rFirst
= mpImplPolygon
->mpPointAry
[ 0 ];
903 if( nOptimizeFlags
& ( POLY_OPTIMIZE_REDUCE
) )
904 nReduce
= pData
? pData
->GetAbsValue() : 4UL;
908 while( nSize
&& ( mpImplPolygon
->mpPointAry
[ nSize
- 1 ] == rFirst
) )
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
];
930 aNewPoly
.SetSize( nNewCount
);
936 nSize
= mpImplPolygon
->mnPoints
;
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
) )
960 // -----------------------------------------------------------------------
962 void Polygon::GetSimple( Polygon
& rResult
) const
964 if( !mpImplPolygon
->mpFlagAry
)
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 ],
982 const USHORT nSegmentSize
= aSegmentPoly
.GetSize();
986 const Point
* pPointArray
= aSegmentPoly
.mpImplPolygon
->mpPointAry
;
987 const Point
* pCur
= pPointArray
;
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
) );
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.
1018 Output iterator, where the subdivided polylines are written to.
1021 Squared difference of curve to a straight line
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
,
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)||
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
1066 recursionDepth
< maxRecursionDepth
&&
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
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
);
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
)
1106 USHORT
nPts( GetSize() );
1107 ::std::vector
< Point
> aPoints
;
1108 aPoints
.reserve( nPts
);
1109 ::std::back_insert_iterator
< ::std::vector
< Point
> > aPointIter( aPoints
);
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() );
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
;
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
) )
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
) )
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
;
1240 double fRelLen
= 1.0 - sqrt( fDistB
/ rArea
);
1244 else if( fRelLen
> 1.0 )
1247 if( ( (UINT32
) ( ( ( fLenFact
- 1.0 ) * 1000000.0 ) + 0.5 ) < fBound
) &&
1248 ( fabs( fGradB
) <= ( fRelLen
* fBound
* 0.01 ) ) )
1250 bDeletePoint
= TRUE
;
1257 aNewPoly
[ nNewPos
++ ] = rPoly
[ n
];
1259 bChangeInThisRun
= TRUE
;
1262 if( bChangeInThisRun
&& nNewPos
)
1264 aNewPoly
.SetSize( nNewPos
);
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
)
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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();
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
;
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
1442 virtual void LastPoint() = 0;
1443 virtual void Input( const Point
& rPoint
) = 0;
1446 class ImplPolygonPointFilter
: public ImplPointFilter
1449 ImplPolygon
* mpPoly
; // Nicht loeschen, wird dem Polygon zugewiesen
1452 ImplPolygonPointFilter( USHORT nDestSize
) :
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]) )
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
1483 ImplPointFilter
& mrNextFilter
;
1491 ImplEdgePointFilter( int nEdge
, long nLow
, long nHigh
,
1492 ImplPointFilter
& rNextFilter
) :
1493 mrNextFilter( rNextFilter
),
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;
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
;
1533 if ( nEdge
& EDGE_VERT
)
1535 nNewY
= (nEdge
== EDGE_TOP
) ? mnLow
: mnHigh
;
1536 long dy
= nNewY
- ly
;
1539 else if ( (LONG_MAX
/ Abs(md
)) >= Abs(dy
) )
1540 nNewX
= (dy
* md
) / mn
+ lx
;
1556 nNewX
= (long)ady
+ lx
;
1561 nNewX
= (nEdge
== EDGE_LEFT
) ? mnLow
: mnHigh
;
1562 long dx
= nNewX
- lx
;
1565 else if ( (LONG_MAX
/ Abs(mn
)) >= Abs(dx
) )
1566 nNewY
= (dx
* mn
) / md
+ ly
;
1582 nNewY
= (long)adx
+ ly
;
1586 return Point( nNewX
, nNewY
);
1589 void ImplEdgePointFilter::Input( const Point
& rPoint
)
1591 int nOutside
= VisibleSide( rPoint
);
1595 maFirstPoint
= rPoint
;
1598 mrNextFilter
.Input( rPoint
);
1600 else if ( rPoint
== maLastPoint
)
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()
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(),
1644 ImplEdgePointFilter
aVertFilter( EDGE_VERT
, aJustifiedRect
.Top(), aJustifiedRect
.Bottom(),
1647 for ( USHORT i
= 0; i
< nSourceSize
; i
++ )
1648 aVertFilter
.Input( mpImplPolygon
->mpPointAry
[i
] );
1649 if ( bPolygon
|| aVertFilter
.IsPolygon() )
1650 aVertFilter
.LastPoint();
1652 aPolygon
.LastPoint();
1654 // Alte ImpPolygon-Daten loeschen und die vom ImpPolygonPointFilter
1656 if ( mpImplPolygon
->mnRefCount
)
1658 if ( mpImplPolygon
->mnRefCount
> 1 )
1659 mpImplPolygon
->mnRefCount
--;
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
;
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
)
1689 if ( pPt
->X() > nXMax
)
1691 if ( pPt
->Y() < nYMin
)
1693 if ( pPt
->Y() > nYMax
)
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!" );
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() );
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 ) )
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
1767 if ( aIntersection
!= aLastIntersection
)
1769 aLastIntersection
= aIntersection
;
1775 aLastIntersection
= aIntersection
;
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
);
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
;
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
) )
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" );
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
--;
1880 delete mpImplPolygon
;
1883 mpImplPolygon
= rPoly
.mpImplPolygon
;
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
) )
1900 // -----------------------------------------------------------------------
1902 sal_Bool
Polygon::IsEqual( const Polygon
& rPoly
) const
1904 sal_Bool bIsEqual
= sal_True
;;
1906 if ( GetSize() != rPoly
.GetSize() )
1907 bIsEqual
= sal_False
;
1910 for ( i
= 0; i
< GetSize(); i
++ )
1912 if ( ( GetPoint( i
) != rPoly
.GetPoint( i
) ) ||
1913 ( GetFlags( i
) != rPoly
.GetFlags( i
) ) )
1915 bIsEqual
= sal_False
;
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" );
1934 unsigned char bShort
;
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
);
1949 rPoly
.mpImplPolygon
->ImplSetSize( nPoints
, FALSE
);
1951 // Je nach CompressMode das Polygon einlesen
1952 if ( rIStream
.GetCompressMode() == COMPRESSMODE_FULL
)
1955 while ( i
< nPoints
)
1957 rIStream
>> bShort
>> nCurPoints
;
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
;
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
;
1981 // Feststellen, ob ueber die Operatoren geschrieben werden muss
1982 #if (SAL_TYPES_SIZEOFLONG) != 4
1985 #ifdef OSL_BIGENDIAN
1986 if ( rIStream
.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN
)
1988 if ( rIStream
.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN
)
1992 for( i
= 0; i
< nPoints
; i
++ )
1994 rIStream
>> rPoly
.mpImplPolygon
->mpPointAry
[i
].X()
1995 >> rPoly
.mpImplPolygon
->mpPointAry
[i
].Y();
1999 rIStream
.Read( rPoly
.mpImplPolygon
->mpPointAry
, nPoints
*sizeof(Point
) );
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
;
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
)
2025 while ( i
< nPoints
)
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
)) )
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
)) )
2048 // Wenn sich die Werte in einen anderen Bereich begeben,
2049 // muessen wir neu rausschreiben
2050 if ( bCurShort
!= bShort
)
2059 rOStream
<< bShort
<< (USHORT
)(i
-nStart
);
2063 for( ; nStart
< i
; nStart
++ )
2065 rOStream
<< (short)rPoly
.mpImplPolygon
->mpPointAry
[nStart
].X()
2066 << (short)rPoly
.mpImplPolygon
->mpPointAry
[nStart
].Y();
2071 for( ; nStart
< i
; nStart
++ )
2073 rOStream
<< rPoly
.mpImplPolygon
->mpPointAry
[nStart
].X()
2074 << rPoly
.mpImplPolygon
->mpPointAry
[nStart
].Y();
2081 // Feststellen, ob ueber die Operatoren geschrieben werden muss
2082 #if (SAL_TYPES_SIZEOFLONG) != 4
2085 #ifdef OSL_BIGENDIAN
2086 if ( rOStream
.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN
)
2088 if ( rOStream
.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN
)
2092 for( i
= 0; i
< nPoints
; i
++ )
2094 rOStream
<< rPoly
.mpImplPolygon
->mpPointAry
[i
].X()
2095 << rPoly
.mpImplPolygon
->mpPointAry
[i
].Y();
2101 rOStream
.Write( rPoly
.mpImplPolygon
->mpPointAry
, nPoints
*sizeof(Point
) );
2108 // -----------------------------------------------------------------------
2110 void Polygon::ImplRead( SvStream
& rIStream
)
2112 sal_uInt8 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
;
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
));
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
);
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
++];
2213 if(a
< nCount
&& POLY_CONTROL
== mpImplPolygon
->mpFlagAry
[a
])
2215 aControlB
= mpImplPolygon
->mpPointAry
[a
++];
2219 // assert invalid polygons
2220 OSL_ENSURE(bControlA
== bControlB
, "Polygon::getB2DPolygon: Invalid source polygon (!)");
2224 const Point
aEndPoint(mpImplPolygon
->mpPointAry
[a
]);
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
);
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]);
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()));
2267 basegfx::tools::checkClosed(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
)
2284 DBG_CTOR( Polygon
, NULL
);
2286 const bool bCurve(rPolygon
.areControlPointsUsed());
2287 const bool bClosed(rPolygon
.isClosed());
2288 sal_uInt32
nB2DLocalCount(rPolygon
.count());
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 ));
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
;
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
;
2335 mpImplPolygon
->mpPointAry
[nArrayInsert
] = Point(FRound(aBezier
.getControlPointB().getX()), FRound(aBezier
.getControlPointB().getY()));
2336 mpImplPolygon
->mpFlagAry
[nArrayInsert
] = (BYTE
)POLY_CONTROL
;
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());
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
;
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
;
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);
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);
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
;
2409 // add first point as closing point
2410 mpImplPolygon
->mpPointAry
[nIndex
] = mpImplPolygon
->mpPointAry
[0];
2417 // no content yet, create empty polygon
2418 mpImplPolygon
= (ImplPolygon
*)(&aStaticImplPolygon
);