xref: /AOO41X/main/tools/source/generic/poly2.cxx (revision ff0525f24f03981d56b7579b645949f111420994)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_tools.hxx"
26 
27 #define _SV_POLY2_CXX
28 
29 #define POLY_CLIP_INT   0
30 #define POLY_CLIP_UNION 1
31 #define POLY_CLIP_DIFF  2
32 #define POLY_CLIP_XOR   3
33 
34 #include <rtl/math.hxx>
35 #include <poly.h>
36 #include <tools/poly.hxx>
37 #include <tools/debug.hxx>
38 #include <tools/stream.hxx>
39 #include <tools/vcompat.hxx>
40 #include <basegfx/polygon/b2dpolypolygon.hxx>
41 #include <basegfx/polygon/b2dpolygon.hxx>
42 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
43 
44 // ---------------
45 // - PolyPolygon -
46 // ---------------
47 
48 DBG_NAME( PolyPolygon )
49 
50 // -----------------------------------------------------------------------
51 
52 ImplPolyPolygon::ImplPolyPolygon( sal_uInt16 nInitSize )
53 {
54     mnRefCount  = 1;
55     mnCount     = nInitSize;
56     mnSize      = nInitSize;
57     mnResize    = 16;
58     mpPolyAry   = new SVPPOLYGON[ nInitSize ];
59 }
60 
61 // -----------------------------------------------------------------------
62 
63 ImplPolyPolygon::ImplPolyPolygon( const ImplPolyPolygon& rImplPolyPoly )
64 {
65     mnRefCount  = 1;
66     mnCount     = rImplPolyPoly.mnCount;
67     mnSize      = rImplPolyPoly.mnSize;
68     mnResize    = rImplPolyPoly.mnResize;
69 
70     if ( rImplPolyPoly.mpPolyAry )
71     {
72         mpPolyAry = new SVPPOLYGON[mnSize];
73         for ( sal_uInt16 i = 0; i < mnCount; i++ )
74             mpPolyAry[i] = new Polygon( *rImplPolyPoly.mpPolyAry[i] );
75     }
76     else
77         mpPolyAry = NULL;
78 }
79 
80 // -----------------------------------------------------------------------
81 
82 ImplPolyPolygon::~ImplPolyPolygon()
83 {
84     if ( mpPolyAry )
85     {
86         for ( sal_uInt16 i = 0; i < mnCount; i++ )
87             delete mpPolyAry[i];
88         delete[] mpPolyAry;
89     }
90 }
91 
92 // =======================================================================
93 
94 PolyPolygon::PolyPolygon( sal_uInt16 nInitSize, sal_uInt16 nResize )
95 {
96     DBG_CTOR( PolyPolygon, NULL );
97 
98     if ( nInitSize > MAX_POLYGONS )
99         nInitSize = MAX_POLYGONS;
100     else if ( !nInitSize )
101         nInitSize = 1;
102     if ( nResize > MAX_POLYGONS )
103         nResize = MAX_POLYGONS;
104     else if ( !nResize )
105         nResize = 1;
106     mpImplPolyPolygon = new ImplPolyPolygon( nInitSize, nResize );
107 }
108 
109 // -----------------------------------------------------------------------
110 
111 PolyPolygon::PolyPolygon( const Polygon& rPoly )
112 {
113     DBG_CTOR( PolyPolygon, NULL );
114 
115     if ( rPoly.GetSize() )
116     {
117         mpImplPolyPolygon = new ImplPolyPolygon( 1 );
118         mpImplPolyPolygon->mpPolyAry[0] = new Polygon( rPoly );
119     }
120     else
121         mpImplPolyPolygon = new ImplPolyPolygon( 16, 16 );
122 }
123 
124 // -----------------------------------------------------------------------
125 
126 PolyPolygon::PolyPolygon( const PolyPolygon& rPolyPoly )
127 {
128     DBG_CTOR( PolyPolygon, NULL );
129     DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
130     DBG_ASSERT( rPolyPoly.mpImplPolyPolygon->mnRefCount < 0xFFFFFFFE, "PolyPolygon: RefCount overflow" );
131 
132     mpImplPolyPolygon = rPolyPoly.mpImplPolyPolygon;
133     mpImplPolyPolygon->mnRefCount++;
134 }
135 
136 // -----------------------------------------------------------------------
137 
138 PolyPolygon::~PolyPolygon()
139 {
140     DBG_DTOR( PolyPolygon, NULL );
141 
142     if ( mpImplPolyPolygon->mnRefCount > 1 )
143         mpImplPolyPolygon->mnRefCount--;
144     else
145         delete mpImplPolyPolygon;
146 }
147 
148 // -----------------------------------------------------------------------
149 
150 void PolyPolygon::Insert( const Polygon& rPoly, sal_uInt16 nPos )
151 {
152     DBG_CHKTHIS( PolyPolygon, NULL );
153 
154     if ( mpImplPolyPolygon->mnCount >= MAX_POLYGONS )
155         return;
156 
157     if ( mpImplPolyPolygon->mnRefCount > 1 )
158     {
159         mpImplPolyPolygon->mnRefCount--;
160         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
161     }
162 
163     if ( nPos > mpImplPolyPolygon->mnCount )
164         nPos = mpImplPolyPolygon->mnCount;
165 
166     if ( !mpImplPolyPolygon->mpPolyAry )
167         mpImplPolyPolygon->mpPolyAry = new SVPPOLYGON[mpImplPolyPolygon->mnSize];
168     else if ( mpImplPolyPolygon->mnCount == mpImplPolyPolygon->mnSize )
169     {
170         sal_uInt16      nOldSize = mpImplPolyPolygon->mnSize;
171         sal_uInt16      nNewSize = nOldSize + mpImplPolyPolygon->mnResize;
172         SVPPOLYGON* pNewAry;
173 
174         if ( nNewSize >= MAX_POLYGONS )
175             nNewSize = MAX_POLYGONS;
176         pNewAry = new SVPPOLYGON[nNewSize];
177         memcpy( pNewAry, mpImplPolyPolygon->mpPolyAry, nPos*sizeof(SVPPOLYGON) );
178         memcpy( pNewAry+nPos+1, mpImplPolyPolygon->mpPolyAry+nPos,
179                 (nOldSize-nPos)*sizeof(SVPPOLYGON) );
180         delete[] mpImplPolyPolygon->mpPolyAry;
181         mpImplPolyPolygon->mpPolyAry = pNewAry;
182         mpImplPolyPolygon->mnSize = nNewSize;
183     }
184     else if ( nPos < mpImplPolyPolygon->mnCount )
185     {
186         memmove( mpImplPolyPolygon->mpPolyAry+nPos+1,
187                  mpImplPolyPolygon->mpPolyAry+nPos,
188                  (mpImplPolyPolygon->mnCount-nPos)*sizeof(SVPPOLYGON) );
189     }
190 
191     mpImplPolyPolygon->mpPolyAry[nPos] = new Polygon( rPoly );
192     mpImplPolyPolygon->mnCount++;
193 }
194 
195 // -----------------------------------------------------------------------
196 
197 void PolyPolygon::Remove( sal_uInt16 nPos )
198 {
199     DBG_CHKTHIS( PolyPolygon, NULL );
200     DBG_ASSERT( nPos < Count(), "PolyPolygon::Remove(): nPos >= nSize" );
201 
202     if ( mpImplPolyPolygon->mnRefCount > 1 )
203     {
204         mpImplPolyPolygon->mnRefCount--;
205         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
206     }
207 
208     delete mpImplPolyPolygon->mpPolyAry[nPos];
209     mpImplPolyPolygon->mnCount--;
210     memmove( mpImplPolyPolygon->mpPolyAry+nPos,
211              mpImplPolyPolygon->mpPolyAry+nPos+1,
212              (mpImplPolyPolygon->mnCount-nPos)*sizeof(SVPPOLYGON) );
213 }
214 
215 // -----------------------------------------------------------------------
216 
217 void PolyPolygon::Replace( const Polygon& rPoly, sal_uInt16 nPos )
218 {
219     DBG_CHKTHIS( PolyPolygon, NULL );
220     DBG_ASSERT( nPos < Count(), "PolyPolygon::Replace(): nPos >= nSize" );
221 
222     if ( mpImplPolyPolygon->mnRefCount > 1 )
223     {
224         mpImplPolyPolygon->mnRefCount--;
225         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
226     }
227 
228     delete mpImplPolyPolygon->mpPolyAry[nPos];
229     mpImplPolyPolygon->mpPolyAry[nPos] = new Polygon( rPoly );
230 }
231 
232 // -----------------------------------------------------------------------
233 
234 const Polygon& PolyPolygon::GetObject( sal_uInt16 nPos ) const
235 {
236     DBG_CHKTHIS( PolyPolygon, NULL );
237     DBG_ASSERT( nPos < Count(), "PolyPolygon::GetObject(): nPos >= nSize" );
238 
239     return *(mpImplPolyPolygon->mpPolyAry[nPos]);
240 }
241 
242 // -----------------------------------------------------------------------
243 
244 sal_Bool PolyPolygon::IsRect() const
245 {
246     sal_Bool bIsRect = sal_False;
247     if ( Count() == 1 )
248         bIsRect = mpImplPolyPolygon->mpPolyAry[ 0 ]->IsRect();
249     return bIsRect;
250 }
251 
252 // -----------------------------------------------------------------------
253 
254 void PolyPolygon::Clear()
255 {
256     DBG_CHKTHIS( PolyPolygon, NULL );
257 
258     if ( mpImplPolyPolygon->mnRefCount > 1 )
259     {
260         mpImplPolyPolygon->mnRefCount--;
261         mpImplPolyPolygon = new ImplPolyPolygon( mpImplPolyPolygon->mnResize,
262                                                  mpImplPolyPolygon->mnResize );
263     }
264     else
265     {
266         if ( mpImplPolyPolygon->mpPolyAry )
267         {
268             for ( sal_uInt16 i = 0; i < mpImplPolyPolygon->mnCount; i++ )
269                 delete mpImplPolyPolygon->mpPolyAry[i];
270             delete[] mpImplPolyPolygon->mpPolyAry;
271             mpImplPolyPolygon->mpPolyAry = NULL;
272             mpImplPolyPolygon->mnCount   = 0;
273             mpImplPolyPolygon->mnSize    = mpImplPolyPolygon->mnResize;
274         }
275     }
276 }
277 
278 // -----------------------------------------------------------------------
279 
280 void PolyPolygon::Optimize( sal_uIntPtr nOptimizeFlags, const PolyOptimizeData* pData )
281 {
282     DBG_CHKTHIS( PolyPolygon, NULL );
283 
284     if(nOptimizeFlags && Count())
285     {
286         // #115630# ImplDrawHatch does not work with beziers included in the polypolygon, take care of that
287         bool bIsCurve(false);
288 
289         for(sal_uInt16 a(0); !bIsCurve && a < Count(); a++)
290         {
291             if((*this)[a].HasFlags())
292             {
293                 bIsCurve = true;
294             }
295         }
296 
297         if(bIsCurve)
298         {
299             OSL_ENSURE(false, "Optimize does *not* support curves, falling back to AdaptiveSubdivide()...");
300             PolyPolygon aPolyPoly;
301 
302             AdaptiveSubdivide(aPolyPoly);
303             aPolyPoly.Optimize(nOptimizeFlags, pData);
304             *this = aPolyPoly;
305         }
306         else
307         {
308             double      fArea;
309             const sal_Bool  bEdges = ( nOptimizeFlags & POLY_OPTIMIZE_EDGES ) == POLY_OPTIMIZE_EDGES;
310             sal_uInt16      nPercent = 0;
311 
312             if( bEdges )
313             {
314                 const Rectangle aBound( GetBoundRect() );
315 
316                 fArea = ( aBound.GetWidth() + aBound.GetHeight() ) * 0.5;
317                 nPercent = pData ? pData->GetPercentValue() : 50;
318                 nOptimizeFlags &= ~POLY_OPTIMIZE_EDGES;
319             }
320 
321             // watch for ref counter
322             if( mpImplPolyPolygon->mnRefCount > 1 )
323             {
324                 mpImplPolyPolygon->mnRefCount--;
325                 mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
326             }
327 
328             // Optimize polygons
329             for( sal_uInt16 i = 0, nPolyCount = mpImplPolyPolygon->mnCount; i < nPolyCount; i++ )
330             {
331                 if( bEdges )
332                 {
333                     mpImplPolyPolygon->mpPolyAry[ i ]->Optimize( POLY_OPTIMIZE_NO_SAME );
334                     Polygon::ImplReduceEdges( *( mpImplPolyPolygon->mpPolyAry[ i ] ), fArea, nPercent );
335                 }
336 
337                 if( nOptimizeFlags )
338                     mpImplPolyPolygon->mpPolyAry[ i ]->Optimize( nOptimizeFlags, pData );
339             }
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