xref: /trunk/main/tools/source/generic/poly2.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_tools.hxx"
30 
31 #define _SV_POLY2_CXX
32 
33 #define POLY_CLIP_INT   0
34 #define POLY_CLIP_UNION 1
35 #define POLY_CLIP_DIFF  2
36 #define POLY_CLIP_XOR   3
37 
38 #include <rtl/math.hxx>
39 #include <poly.h>
40 #include <tools/poly.hxx>
41 #include <tools/debug.hxx>
42 #include <tools/stream.hxx>
43 #include <tools/vcompat.hxx>
44 #include <basegfx/polygon/b2dpolypolygon.hxx>
45 #include <basegfx/polygon/b2dpolygon.hxx>
46 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
47 
48 // ---------------
49 // - PolyPolygon -
50 // ---------------
51 
52 DBG_NAME( PolyPolygon )
53 
54 // -----------------------------------------------------------------------
55 
56 ImplPolyPolygon::ImplPolyPolygon( sal_uInt16 nInitSize )
57 {
58     mnRefCount  = 1;
59     mnCount     = nInitSize;
60     mnSize      = nInitSize;
61     mnResize    = 16;
62     mpPolyAry   = new SVPPOLYGON[ nInitSize ];
63 }
64 
65 // -----------------------------------------------------------------------
66 
67 ImplPolyPolygon::ImplPolyPolygon( const ImplPolyPolygon& rImplPolyPoly )
68 {
69     mnRefCount  = 1;
70     mnCount     = rImplPolyPoly.mnCount;
71     mnSize      = rImplPolyPoly.mnSize;
72     mnResize    = rImplPolyPoly.mnResize;
73 
74     if ( rImplPolyPoly.mpPolyAry )
75     {
76         mpPolyAry = new SVPPOLYGON[mnSize];
77         for ( sal_uInt16 i = 0; i < mnCount; i++ )
78             mpPolyAry[i] = new Polygon( *rImplPolyPoly.mpPolyAry[i] );
79     }
80     else
81         mpPolyAry = NULL;
82 }
83 
84 // -----------------------------------------------------------------------
85 
86 ImplPolyPolygon::~ImplPolyPolygon()
87 {
88     if ( mpPolyAry )
89     {
90         for ( sal_uInt16 i = 0; i < mnCount; i++ )
91             delete mpPolyAry[i];
92         delete[] mpPolyAry;
93     }
94 }
95 
96 // =======================================================================
97 
98 PolyPolygon::PolyPolygon( sal_uInt16 nInitSize, sal_uInt16 nResize )
99 {
100     DBG_CTOR( PolyPolygon, NULL );
101 
102     if ( nInitSize > MAX_POLYGONS )
103         nInitSize = MAX_POLYGONS;
104     else if ( !nInitSize )
105         nInitSize = 1;
106     if ( nResize > MAX_POLYGONS )
107         nResize = MAX_POLYGONS;
108     else if ( !nResize )
109         nResize = 1;
110     mpImplPolyPolygon = new ImplPolyPolygon( nInitSize, nResize );
111 }
112 
113 // -----------------------------------------------------------------------
114 
115 PolyPolygon::PolyPolygon( const Polygon& rPoly )
116 {
117     DBG_CTOR( PolyPolygon, NULL );
118 
119     if ( rPoly.GetSize() )
120     {
121         mpImplPolyPolygon = new ImplPolyPolygon( 1 );
122         mpImplPolyPolygon->mpPolyAry[0] = new Polygon( rPoly );
123     }
124     else
125         mpImplPolyPolygon = new ImplPolyPolygon( 16, 16 );
126 }
127 
128 // -----------------------------------------------------------------------
129 
130 PolyPolygon::PolyPolygon( sal_uInt16 nPoly, const sal_uInt16* pPointCountAry,
131                           const Point* pPtAry )
132 {
133     DBG_CTOR( PolyPolygon, NULL );
134 
135     if ( nPoly > MAX_POLYGONS )
136         nPoly = MAX_POLYGONS;
137 
138     mpImplPolyPolygon = new ImplPolyPolygon( nPoly );
139     for ( sal_uInt16 i = 0; i < nPoly; i++ )
140     {
141         mpImplPolyPolygon->mpPolyAry[i] = new Polygon( *pPointCountAry, pPtAry );
142         pPtAry += *pPointCountAry;
143         pPointCountAry++;
144     }
145 }
146 
147 // -----------------------------------------------------------------------
148 
149 PolyPolygon::PolyPolygon( const PolyPolygon& rPolyPoly )
150 {
151     DBG_CTOR( PolyPolygon, NULL );
152     DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
153     DBG_ASSERT( rPolyPoly.mpImplPolyPolygon->mnRefCount < 0xFFFFFFFE, "PolyPolygon: RefCount overflow" );
154 
155     mpImplPolyPolygon = rPolyPoly.mpImplPolyPolygon;
156     mpImplPolyPolygon->mnRefCount++;
157 }
158 
159 // -----------------------------------------------------------------------
160 
161 PolyPolygon::~PolyPolygon()
162 {
163     DBG_DTOR( PolyPolygon, NULL );
164 
165     if ( mpImplPolyPolygon->mnRefCount > 1 )
166         mpImplPolyPolygon->mnRefCount--;
167     else
168         delete mpImplPolyPolygon;
169 }
170 
171 // -----------------------------------------------------------------------
172 
173 void PolyPolygon::Insert( const Polygon& rPoly, sal_uInt16 nPos )
174 {
175     DBG_CHKTHIS( PolyPolygon, NULL );
176 
177     if ( mpImplPolyPolygon->mnCount >= MAX_POLYGONS )
178         return;
179 
180     if ( mpImplPolyPolygon->mnRefCount > 1 )
181     {
182         mpImplPolyPolygon->mnRefCount--;
183         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
184     }
185 
186     if ( nPos > mpImplPolyPolygon->mnCount )
187         nPos = mpImplPolyPolygon->mnCount;
188 
189     if ( !mpImplPolyPolygon->mpPolyAry )
190         mpImplPolyPolygon->mpPolyAry = new SVPPOLYGON[mpImplPolyPolygon->mnSize];
191     else if ( mpImplPolyPolygon->mnCount == mpImplPolyPolygon->mnSize )
192     {
193         sal_uInt16      nOldSize = mpImplPolyPolygon->mnSize;
194         sal_uInt16      nNewSize = nOldSize + mpImplPolyPolygon->mnResize;
195         SVPPOLYGON* pNewAry;
196 
197         if ( nNewSize >= MAX_POLYGONS )
198             nNewSize = MAX_POLYGONS;
199         pNewAry = new SVPPOLYGON[nNewSize];
200         memcpy( pNewAry, mpImplPolyPolygon->mpPolyAry, nPos*sizeof(SVPPOLYGON) );
201         memcpy( pNewAry+nPos+1, mpImplPolyPolygon->mpPolyAry+nPos,
202                 (nOldSize-nPos)*sizeof(SVPPOLYGON) );
203         delete[] mpImplPolyPolygon->mpPolyAry;
204         mpImplPolyPolygon->mpPolyAry = pNewAry;
205         mpImplPolyPolygon->mnSize = nNewSize;
206     }
207     else if ( nPos < mpImplPolyPolygon->mnCount )
208     {
209         memmove( mpImplPolyPolygon->mpPolyAry+nPos+1,
210                  mpImplPolyPolygon->mpPolyAry+nPos,
211                  (mpImplPolyPolygon->mnCount-nPos)*sizeof(SVPPOLYGON) );
212     }
213 
214     mpImplPolyPolygon->mpPolyAry[nPos] = new Polygon( rPoly );
215     mpImplPolyPolygon->mnCount++;
216 }
217 
218 // -----------------------------------------------------------------------
219 
220 void PolyPolygon::Remove( sal_uInt16 nPos )
221 {
222     DBG_CHKTHIS( PolyPolygon, NULL );
223     DBG_ASSERT( nPos < Count(), "PolyPolygon::Remove(): nPos >= nSize" );
224 
225     if ( mpImplPolyPolygon->mnRefCount > 1 )
226     {
227         mpImplPolyPolygon->mnRefCount--;
228         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
229     }
230 
231     delete mpImplPolyPolygon->mpPolyAry[nPos];
232     mpImplPolyPolygon->mnCount--;
233     memmove( mpImplPolyPolygon->mpPolyAry+nPos,
234              mpImplPolyPolygon->mpPolyAry+nPos+1,
235              (mpImplPolyPolygon->mnCount-nPos)*sizeof(SVPPOLYGON) );
236 }
237 
238 // -----------------------------------------------------------------------
239 
240 void PolyPolygon::Replace( const Polygon& rPoly, sal_uInt16 nPos )
241 {
242     DBG_CHKTHIS( PolyPolygon, NULL );
243     DBG_ASSERT( nPos < Count(), "PolyPolygon::Replace(): nPos >= nSize" );
244 
245     if ( mpImplPolyPolygon->mnRefCount > 1 )
246     {
247         mpImplPolyPolygon->mnRefCount--;
248         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
249     }
250 
251     delete mpImplPolyPolygon->mpPolyAry[nPos];
252     mpImplPolyPolygon->mpPolyAry[nPos] = new Polygon( rPoly );
253 }
254 
255 // -----------------------------------------------------------------------
256 
257 const Polygon& PolyPolygon::GetObject( sal_uInt16 nPos ) const
258 {
259     DBG_CHKTHIS( PolyPolygon, NULL );
260     DBG_ASSERT( nPos < Count(), "PolyPolygon::GetObject(): nPos >= nSize" );
261 
262     return *(mpImplPolyPolygon->mpPolyAry[nPos]);
263 }
264 
265 // -----------------------------------------------------------------------
266 
267 sal_Bool PolyPolygon::IsRect() const
268 {
269     sal_Bool bIsRect = sal_False;
270     if ( Count() == 1 )
271         bIsRect = mpImplPolyPolygon->mpPolyAry[ 0 ]->IsRect();
272     return bIsRect;
273 }
274 
275 // -----------------------------------------------------------------------
276 
277 void PolyPolygon::Clear()
278 {
279     DBG_CHKTHIS( PolyPolygon, NULL );
280 
281     if ( mpImplPolyPolygon->mnRefCount > 1 )
282     {
283         mpImplPolyPolygon->mnRefCount--;
284         mpImplPolyPolygon = new ImplPolyPolygon( mpImplPolyPolygon->mnResize,
285                                                  mpImplPolyPolygon->mnResize );
286     }
287     else
288     {
289         if ( mpImplPolyPolygon->mpPolyAry )
290         {
291             for ( sal_uInt16 i = 0; i < mpImplPolyPolygon->mnCount; i++ )
292                 delete mpImplPolyPolygon->mpPolyAry[i];
293             delete[] mpImplPolyPolygon->mpPolyAry;
294             mpImplPolyPolygon->mpPolyAry = NULL;
295             mpImplPolyPolygon->mnCount   = 0;
296             mpImplPolyPolygon->mnSize    = mpImplPolyPolygon->mnResize;
297         }
298     }
299 }
300 
301 // -----------------------------------------------------------------------
302 
303 void PolyPolygon::Optimize( sal_uIntPtr nOptimizeFlags, const PolyOptimizeData* pData )
304 {
305     DBG_CHKTHIS( PolyPolygon, NULL );
306 
307     if( nOptimizeFlags )
308     {
309         double      fArea;
310         const sal_Bool  bEdges = ( nOptimizeFlags & POLY_OPTIMIZE_EDGES ) == POLY_OPTIMIZE_EDGES;
311         sal_uInt16      nPercent = 0;
312 
313         if( bEdges )
314         {
315             const Rectangle aBound( GetBoundRect() );
316 
317             fArea = ( aBound.GetWidth() + aBound.GetHeight() ) * 0.5;
318             nPercent = pData ? pData->GetPercentValue() : 50;
319             nOptimizeFlags &= ~POLY_OPTIMIZE_EDGES;
320         }
321 
322         // watch for ref counter
323         if( mpImplPolyPolygon->mnRefCount > 1 )
324         {
325             mpImplPolyPolygon->mnRefCount--;
326             mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
327         }
328 
329         // Optimize polygons
330         for( sal_uInt16 i = 0, nPolyCount = mpImplPolyPolygon->mnCount; i < nPolyCount; i++ )
331         {
332             if( bEdges )
333             {
334                 mpImplPolyPolygon->mpPolyAry[ i ]->Optimize( POLY_OPTIMIZE_NO_SAME );
335                 Polygon::ImplReduceEdges( *( mpImplPolyPolygon->mpPolyAry[ i ] ), fArea, nPercent );
336             }
337 
338             if( nOptimizeFlags )
339                 mpImplPolyPolygon->mpPolyAry[ i ]->Optimize( nOptimizeFlags, pData );
340         }
341     }
342 }
343 
344 // -----------------------------------------------------------------------
345 
346 void PolyPolygon::AdaptiveSubdivide( PolyPolygon& rResult, const double d ) const
347 {
348     DBG_CHKTHIS( PolyPolygon, NULL );
349 
350     rResult.Clear();
351 
352     Polygon aPolygon;
353 
354     for( sal_uInt16 i = 0; i < mpImplPolyPolygon->mnCount; i++ )
355     {
356         mpImplPolyPolygon->mpPolyAry[ i ]->AdaptiveSubdivide( aPolygon, d );
357         rResult.Insert( aPolygon );
358     }
359 }
360 
361 // -----------------------------------------------------------------------
362 
363 void PolyPolygon::GetIntersection( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
364 {
365     ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_INT );
366 }
367 
368 // -----------------------------------------------------------------------
369 
370 void PolyPolygon::GetUnion( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
371 {
372     ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_UNION );
373 }
374 
375 // -----------------------------------------------------------------------
376 
377 void PolyPolygon::GetDifference( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
378 {
379     ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_DIFF );
380 }
381 
382 // -----------------------------------------------------------------------
383 
384 void PolyPolygon::GetXOR( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
385 {
386     ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_XOR );
387 }
388 
389 // -----------------------------------------------------------------------
390 
391 void PolyPolygon::ImplDoOperation( const PolyPolygon& rPolyPoly, PolyPolygon& rResult, sal_uIntPtr nOperation ) const
392 {
393     // Convert to B2DPolyPolygon, temporarily. It might be
394     // advantageous in the future, to have a PolyPolygon adaptor that
395     // just simulates a B2DPolyPolygon here...
396     basegfx::B2DPolyPolygon aMergePolyPolygonA( getB2DPolyPolygon() );
397     basegfx::B2DPolyPolygon aMergePolyPolygonB( rPolyPoly.getB2DPolyPolygon() );
398 
399     // normalize the two polypolygons before. Force properly oriented
400     // polygons.
401     aMergePolyPolygonA = basegfx::tools::prepareForPolygonOperation( aMergePolyPolygonA );
402     aMergePolyPolygonB = basegfx::tools::prepareForPolygonOperation( aMergePolyPolygonB );
403 
404     switch( nOperation )
405     {
406         // All code extracted from svx/source/svdraw/svedtv2.cxx
407         // -----------------------------------------------------
408 
409         case POLY_CLIP_UNION:
410         {
411             // merge A and B (OR)
412             aMergePolyPolygonA = basegfx::tools::solvePolygonOperationOr(aMergePolyPolygonA, aMergePolyPolygonB);
413             break;
414         }
415 
416         case POLY_CLIP_DIFF:
417         {
418             // substract B from A (DIFF)
419             aMergePolyPolygonA = basegfx::tools::solvePolygonOperationDiff(aMergePolyPolygonA, aMergePolyPolygonB);
420             break;
421         }
422 
423         case POLY_CLIP_XOR:
424         {
425             // compute XOR between poly A and B
426             aMergePolyPolygonA = basegfx::tools::solvePolygonOperationXor(aMergePolyPolygonA, aMergePolyPolygonB);
427             break;
428         }
429 
430         default:
431         case POLY_CLIP_INT:
432         {
433             // cut poly 1 against polys 2..n (AND)
434             aMergePolyPolygonA = basegfx::tools::solvePolygonOperationAnd(aMergePolyPolygonA, aMergePolyPolygonB);
435             break;
436         }
437     }
438 
439     rResult = PolyPolygon( aMergePolyPolygonA );
440 }
441 
442 // -----------------------------------------------------------------------
443 
444 sal_uInt16 PolyPolygon::Count() const
445 {
446     DBG_CHKTHIS( PolyPolygon, NULL );
447     return mpImplPolyPolygon->mnCount;
448 }
449 
450 // -----------------------------------------------------------------------
451 
452 void PolyPolygon::Move( long nHorzMove, long nVertMove )
453 {
454     DBG_CHKTHIS( PolyPolygon, NULL );
455 
456     // Diese Abfrage sollte man fuer die DrawEngine durchfuehren
457     if( nHorzMove || nVertMove )
458     {
459         // Referenzcounter beruecksichtigen
460         if ( mpImplPolyPolygon->mnRefCount > 1 )
461         {
462             mpImplPolyPolygon->mnRefCount--;
463             mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
464         }
465 
466         // Punkte verschieben
467         sal_uInt16 nPolyCount = mpImplPolyPolygon->mnCount;
468         for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
469             mpImplPolyPolygon->mpPolyAry[i]->Move( nHorzMove, nVertMove );
470     }
471 }
472 
473 // -----------------------------------------------------------------------
474 
475 void PolyPolygon::Translate( const Point& rTrans )
476 {
477     DBG_CHKTHIS( PolyPolygon, NULL );
478 
479     // Referenzcounter beruecksichtigen
480     if( mpImplPolyPolygon->mnRefCount > 1 )
481     {
482         mpImplPolyPolygon->mnRefCount--;
483         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
484     }
485 
486     // Punkte verschieben
487     for ( sal_uInt16 i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
488         mpImplPolyPolygon->mpPolyAry[ i ]->Translate( rTrans );
489 }
490 
491 // -----------------------------------------------------------------------
492 
493 void PolyPolygon::Scale( double fScaleX, double fScaleY )
494 {
495     DBG_CHKTHIS( PolyPolygon, NULL );
496 
497     // Referenzcounter beruecksichtigen
498     if( mpImplPolyPolygon->mnRefCount > 1 )
499     {
500         mpImplPolyPolygon->mnRefCount--;
501         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
502     }
503 
504     // Punkte verschieben
505     for ( sal_uInt16 i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
506         mpImplPolyPolygon->mpPolyAry[ i ]->Scale( fScaleX, fScaleY );
507 }
508 
509 // -----------------------------------------------------------------------
510 
511 void PolyPolygon::Rotate( const Point& rCenter, sal_uInt16 nAngle10 )
512 {
513     DBG_CHKTHIS( PolyPolygon, NULL );
514     nAngle10 %= 3600;
515 
516     if( nAngle10 )
517     {
518         const double fAngle = F_PI1800 * nAngle10;
519         Rotate( rCenter, sin( fAngle ), cos( fAngle ) );
520     }
521 }
522 
523 // -----------------------------------------------------------------------
524 
525 void PolyPolygon::Rotate( const Point& rCenter, double fSin, double fCos )
526 {
527     DBG_CHKTHIS( PolyPolygon, NULL );
528 
529     // Referenzcounter beruecksichtigen
530     if( mpImplPolyPolygon->mnRefCount > 1 )
531     {
532         mpImplPolyPolygon->mnRefCount--;
533         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
534     }
535 
536     // Punkte verschieben
537     for ( sal_uInt16 i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
538         mpImplPolyPolygon->mpPolyAry[ i ]->Rotate( rCenter, fSin, fCos );
539 }
540 
541 // -----------------------------------------------------------------------
542 
543 void PolyPolygon::SlantX( long nYRef, double fSin, double fCos )
544 {
545     DBG_CHKTHIS( PolyPolygon, NULL );
546 
547     // Referenzcounter beruecksichtigen
548     if( mpImplPolyPolygon->mnRefCount > 1 )
549     {
550         mpImplPolyPolygon->mnRefCount--;
551         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
552     }
553 
554     // Punkte verschieben
555     for ( sal_uInt16 i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
556         mpImplPolyPolygon->mpPolyAry[ i ]->SlantX( nYRef, fSin, fCos );
557 }
558 
559 // -----------------------------------------------------------------------
560 
561 void PolyPolygon::SlantY( long nXRef, double fSin, double fCos )
562 {
563     DBG_CHKTHIS( PolyPolygon, NULL );
564 
565     // Referenzcounter beruecksichtigen
566     if( mpImplPolyPolygon->mnRefCount > 1 )
567     {
568         mpImplPolyPolygon->mnRefCount--;
569         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
570     }
571 
572     // Punkte verschieben
573     for ( sal_uInt16 i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
574         mpImplPolyPolygon->mpPolyAry[ i ]->SlantY( nXRef, fSin, fCos );
575 }
576 
577 // -----------------------------------------------------------------------
578 
579 void PolyPolygon::Distort( const Rectangle& rRefRect, const Polygon& rDistortedRect )
580 {
581     DBG_CHKTHIS( PolyPolygon, NULL );
582 
583     // Referenzcounter beruecksichtigen
584     if( mpImplPolyPolygon->mnRefCount > 1 )
585     {
586         mpImplPolyPolygon->mnRefCount--;
587         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
588     }
589 
590     // Punkte verschieben
591     for ( sal_uInt16 i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
592         mpImplPolyPolygon->mpPolyAry[ i ]->Distort( rRefRect, rDistortedRect );
593 }
594 
595 
596 // -----------------------------------------------------------------------
597 
598 void PolyPolygon::Clip( const Rectangle& rRect )
599 {
600     // Polygon-Clippen
601     sal_uInt16 nPolyCount = mpImplPolyPolygon->mnCount;
602     sal_uInt16 i;
603 
604     if ( !nPolyCount )
605         return;
606 
607     // Referenzcounter beruecksichtigen
608     if ( mpImplPolyPolygon->mnRefCount > 1 )
609     {
610         mpImplPolyPolygon->mnRefCount--;
611         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
612     }
613 
614     // Erst jedes Polygon Clippen und dann die leeren entfernen
615     for ( i = 0; i < nPolyCount; i++ )
616         mpImplPolyPolygon->mpPolyAry[i]->Clip( rRect );
617     while ( nPolyCount )
618     {
619         if ( GetObject( nPolyCount-1 ).GetSize() <= 2 )
620             Remove( nPolyCount-1 );
621         nPolyCount--;
622     }
623 }
624 
625 // -----------------------------------------------------------------------
626 
627 Rectangle PolyPolygon::GetBoundRect() const
628 {
629     DBG_CHKTHIS( PolyPolygon, NULL );
630 
631     long    nXMin=0, nXMax=0, nYMin=0, nYMax=0;
632     sal_Bool    bFirst = sal_True;
633     sal_uInt16  nPolyCount = mpImplPolyPolygon->mnCount;
634 
635     for ( sal_uInt16 n = 0; n < nPolyCount; n++ )
636     {
637         const Polygon*  pPoly = mpImplPolyPolygon->mpPolyAry[n];
638         const Point*    pAry = pPoly->GetConstPointAry();
639         sal_uInt16          nPointCount = pPoly->GetSize();
640 
641         for ( sal_uInt16 i = 0; i < nPointCount; i++ )
642         {
643             const Point* pPt = &pAry[ i ];
644 
645             if ( bFirst )
646             {
647                 nXMin = nXMax = pPt->X();
648                 nYMin = nYMax = pPt->Y();
649                 bFirst = sal_False;
650             }
651             else
652             {
653                 if ( pPt->X() < nXMin )
654                     nXMin = pPt->X();
655                 if ( pPt->X() > nXMax )
656                     nXMax = pPt->X();
657                 if ( pPt->Y() < nYMin )
658                     nYMin = pPt->Y();
659                 if ( pPt->Y() > nYMax )
660                     nYMax = pPt->Y();
661             }
662         }
663     }
664 
665     if ( !bFirst )
666         return Rectangle( nXMin, nYMin, nXMax, nYMax );
667     else
668         return Rectangle();
669 }
670 
671 // -----------------------------------------------------------------------
672 
673 Polygon& PolyPolygon::operator[]( sal_uInt16 nPos )
674 {
675     DBG_CHKTHIS( PolyPolygon, NULL );
676     DBG_ASSERT( nPos < Count(), "PolyPolygon::[](): nPos >= nSize" );
677 
678     if ( mpImplPolyPolygon->mnRefCount > 1 )
679     {
680         mpImplPolyPolygon->mnRefCount--;
681         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
682     }
683 
684     return *(mpImplPolyPolygon->mpPolyAry[nPos]);
685 }
686 
687 // -----------------------------------------------------------------------
688 
689 PolyPolygon& PolyPolygon::operator=( const PolyPolygon& rPolyPoly )
690 {
691     DBG_CHKTHIS( PolyPolygon, NULL );
692     DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
693     DBG_ASSERT( rPolyPoly.mpImplPolyPolygon->mnRefCount < 0xFFFFFFFE, "PolyPolygon: RefCount overflow" );
694 
695     rPolyPoly.mpImplPolyPolygon->mnRefCount++;
696 
697     if ( mpImplPolyPolygon->mnRefCount > 1 )
698         mpImplPolyPolygon->mnRefCount--;
699     else
700         delete mpImplPolyPolygon;
701 
702     mpImplPolyPolygon = rPolyPoly.mpImplPolyPolygon;
703     return *this;
704 }
705 
706 // -----------------------------------------------------------------------
707 
708 sal_Bool PolyPolygon::operator==( const PolyPolygon& rPolyPoly ) const
709 {
710     DBG_CHKTHIS( PolyPolygon, NULL );
711     DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
712 
713     if ( rPolyPoly.mpImplPolyPolygon == mpImplPolyPolygon )
714         return sal_True;
715     else
716         return sal_False;
717 }
718 
719 // -----------------------------------------------------------------------
720 
721 sal_Bool PolyPolygon::IsEqual( const PolyPolygon& rPolyPoly ) const
722 {
723     sal_Bool bIsEqual = sal_True;
724     if ( Count() != rPolyPoly.Count() )
725         bIsEqual = sal_False;
726     else
727     {
728         sal_uInt16 i;
729         for ( i = 0; i < Count(); i++ )
730         {
731             if (!GetObject( i ).IsEqual( rPolyPoly.GetObject( i ) ) )
732             {
733                 bIsEqual = sal_False;
734                 break;
735             }
736         }
737     }
738     return bIsEqual;
739 }
740 
741 // -----------------------------------------------------------------------
742 
743 SvStream& operator>>( SvStream& rIStream, PolyPolygon& rPolyPoly )
744 {
745     DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
746     DBG_ASSERTWARNING( rIStream.GetVersion(), "PolyPolygon::>> - Solar-Version not set on rIStream" );
747 
748     Polygon* pPoly;
749     sal_uInt16   nPolyCount;
750 
751     // Anzahl der Polygone einlesen
752     rIStream >> nPolyCount;
753 
754     // Daten anlegen
755     if( nPolyCount )
756     {
757         // Referenzcounter beruecksichtigen
758         if ( rPolyPoly.mpImplPolyPolygon->mnRefCount > 1 )
759             rPolyPoly.mpImplPolyPolygon->mnRefCount--;
760         else
761             delete rPolyPoly.mpImplPolyPolygon;
762 
763         rPolyPoly.mpImplPolyPolygon = new ImplPolyPolygon( nPolyCount );
764 
765         for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
766         {
767             pPoly = new Polygon;
768             rIStream >> *pPoly;
769             rPolyPoly.mpImplPolyPolygon->mpPolyAry[i] = pPoly;
770         }
771     }
772     else
773         rPolyPoly = PolyPolygon();
774 
775     return rIStream;
776 }
777 
778 // -----------------------------------------------------------------------
779 
780 SvStream& operator<<( SvStream& rOStream, const PolyPolygon& rPolyPoly )
781 {
782     DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
783     DBG_ASSERTWARNING( rOStream.GetVersion(), "PolyPolygon::<< - Solar-Version not set on rOStream" );
784 
785     // Anzahl der Polygone rausschreiben
786     sal_uInt16 nPolyCount = rPolyPoly.mpImplPolyPolygon->mnCount;
787     rOStream << nPolyCount;
788 
789     // Die einzelnen Polygone ausgeben
790     for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
791         rOStream << *(rPolyPoly.mpImplPolyPolygon->mpPolyAry[i]);
792 
793     return rOStream;
794 }
795 
796 // -----------------------------------------------------------------------
797 
798 void PolyPolygon::Read( SvStream& rIStream )
799 {
800     VersionCompat aCompat( rIStream, STREAM_READ );
801 
802     DBG_CHKTHIS( PolyPolygon, NULL );
803     DBG_ASSERTWARNING( rIStream.GetVersion(), "PolyPolygon::>> - Solar-Version not set on rIStream" );
804 
805     Polygon* pPoly;
806     sal_uInt16   nPolyCount;
807 
808     // Anzahl der Polygone einlesen
809     rIStream >> nPolyCount;
810 
811     // Daten anlegen
812     if( nPolyCount )
813     {
814         // Referenzcounter beruecksichtigen
815         if ( mpImplPolyPolygon->mnRefCount > 1 )
816             mpImplPolyPolygon->mnRefCount--;
817         else
818             delete mpImplPolyPolygon;
819 
820         mpImplPolyPolygon = new ImplPolyPolygon( nPolyCount );
821 
822         for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
823         {
824             pPoly = new Polygon;
825             pPoly->ImplRead( rIStream );
826             mpImplPolyPolygon->mpPolyAry[i] = pPoly;
827         }
828     }
829     else
830         *this = PolyPolygon();
831 }
832 
833 // -----------------------------------------------------------------------
834 
835 void PolyPolygon::Write( SvStream& rOStream ) const
836 {
837     VersionCompat aCompat( rOStream, STREAM_WRITE, 1 );
838 
839     DBG_CHKTHIS( PolyPolygon, NULL );
840     DBG_ASSERTWARNING( rOStream.GetVersion(), "PolyPolygon::<< - Solar-Version not set on rOStream" );
841 
842     // Anzahl der Polygone rausschreiben
843     sal_uInt16 nPolyCount = mpImplPolyPolygon->mnCount;
844     rOStream << nPolyCount;
845 
846     // Die einzelnen Polygone ausgeben
847     for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
848         mpImplPolyPolygon->mpPolyAry[i]->ImplWrite( rOStream );;
849 }
850 
851 // -----------------------------------------------------------------------
852 // convert to basegfx::B2DPolyPolygon and return
853 basegfx::B2DPolyPolygon PolyPolygon::getB2DPolyPolygon() const
854 {
855     basegfx::B2DPolyPolygon aRetval;
856 
857     for(sal_uInt16 a(0); a < mpImplPolyPolygon->mnCount; a++)
858     {
859         Polygon* pCandidate = mpImplPolyPolygon->mpPolyAry[a];
860         aRetval.append(pCandidate->getB2DPolygon());
861     }
862 
863     return aRetval;
864 }
865 
866 // -----------------------------------------------------------------------
867 // constructor to convert from basegfx::B2DPolyPolygon
868 PolyPolygon::PolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon)
869 {
870     DBG_CTOR( PolyPolygon, NULL );
871     const sal_uInt16 nCount(sal_uInt16(rPolyPolygon.count()));
872     DBG_ASSERT(sal_uInt32(nCount) == rPolyPolygon.count(),
873         "PolyPolygon::PolyPolygon: Too many sub-polygons in given basegfx::B2DPolyPolygon (!)");
874 
875     if ( nCount )
876     {
877         mpImplPolyPolygon = new ImplPolyPolygon( nCount );
878 
879         for(sal_uInt16 a(0); a < nCount; a++)
880         {
881             basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(sal_uInt32(a)));
882             mpImplPolyPolygon->mpPolyAry[a] = new Polygon( aCandidate );
883         }
884     }
885     else
886     {
887         mpImplPolyPolygon = new ImplPolyPolygon( 16, 16 );
888     }
889 }
890 
891 // eof
892