xref: /AOO41X/main/tools/source/generic/poly2.cxx (revision 7566a17ca5be0ee1e8941ab62b027af4e6ca3a04)
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 
DBG_NAME(PolyPolygon)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 
ImplPolyPolygon(const ImplPolyPolygon & rImplPolyPoly)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 
~ImplPolyPolygon()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 
PolyPolygon(sal_uInt16 nInitSize,sal_uInt16 nResize)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 
PolyPolygon(const Polygon & rPoly)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 
PolyPolygon(const PolyPolygon & rPolyPoly)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 
~PolyPolygon()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 
Insert(const Polygon & rPoly,sal_uInt16 nPos)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 
Remove(sal_uInt16 nPos)197 void PolyPolygon::Remove( sal_uInt16 nPos )
198 {
199     DBG_CHKTHIS( PolyPolygon, NULL );
200     DBG_ASSERT( nPos < Count(), "PolyPolygon::Remove(): nPos >= nSize" );
201     if ( nPos >= Count() ) return; // not removable
202 
203     if ( mpImplPolyPolygon->mnRefCount > 1 )
204     {
205         mpImplPolyPolygon->mnRefCount--;
206         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
207     }
208 
209     delete mpImplPolyPolygon->mpPolyAry[nPos];
210     mpImplPolyPolygon->mnCount--;
211     memmove( mpImplPolyPolygon->mpPolyAry+nPos,
212              mpImplPolyPolygon->mpPolyAry+nPos+1,
213              (mpImplPolyPolygon->mnCount-nPos)*sizeof(SVPPOLYGON) );
214 }
215 
216 // -----------------------------------------------------------------------
217 
Replace(const Polygon & rPoly,sal_uInt16 nPos)218 void PolyPolygon::Replace( const Polygon& rPoly, sal_uInt16 nPos )
219 {
220     DBG_CHKTHIS( PolyPolygon, NULL );
221     DBG_ASSERT( nPos < Count(), "PolyPolygon::Replace(): nPos >= nSize" );
222     if ( nPos >= Count() ) return; // not replaceable
223 
224     if ( mpImplPolyPolygon->mnRefCount > 1 )
225     {
226         mpImplPolyPolygon->mnRefCount--;
227         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
228     }
229 
230     delete mpImplPolyPolygon->mpPolyAry[nPos];
231     mpImplPolyPolygon->mpPolyAry[nPos] = new Polygon( rPoly );
232 }
233 
234 // -----------------------------------------------------------------------
235 
GetObject(sal_uInt16 nPos) const236 const Polygon& PolyPolygon::GetObject( sal_uInt16 nPos ) const
237 {
238     DBG_CHKTHIS( PolyPolygon, NULL );
239     DBG_ASSERT( nPos < Count(), "PolyPolygon::GetObject(): nPos >= nSize" );
240 
241     return *(mpImplPolyPolygon->mpPolyAry[nPos]);
242 }
243 
244 // -----------------------------------------------------------------------
245 
IsRect() const246 sal_Bool PolyPolygon::IsRect() const
247 {
248     sal_Bool bIsRect = sal_False;
249     if ( Count() == 1 )
250         bIsRect = mpImplPolyPolygon->mpPolyAry[ 0 ]->IsRect();
251     return bIsRect;
252 }
253 
254 // -----------------------------------------------------------------------
255 
Clear()256 void PolyPolygon::Clear()
257 {
258     DBG_CHKTHIS( PolyPolygon, NULL );
259 
260     if ( mpImplPolyPolygon->mnRefCount > 1 )
261     {
262         mpImplPolyPolygon->mnRefCount--;
263         mpImplPolyPolygon = new ImplPolyPolygon( mpImplPolyPolygon->mnResize,
264                                                  mpImplPolyPolygon->mnResize );
265     }
266     else
267     {
268         if ( mpImplPolyPolygon->mpPolyAry )
269         {
270             for ( sal_uInt16 i = 0; i < mpImplPolyPolygon->mnCount; i++ )
271                 delete mpImplPolyPolygon->mpPolyAry[i];
272             delete[] mpImplPolyPolygon->mpPolyAry;
273             mpImplPolyPolygon->mpPolyAry = NULL;
274             mpImplPolyPolygon->mnCount   = 0;
275             mpImplPolyPolygon->mnSize    = mpImplPolyPolygon->mnResize;
276         }
277     }
278 }
279 
280 // -----------------------------------------------------------------------
281 
Optimize(sal_uIntPtr nOptimizeFlags,const PolyOptimizeData * pData)282 void PolyPolygon::Optimize( sal_uIntPtr nOptimizeFlags, const PolyOptimizeData* pData )
283 {
284     DBG_CHKTHIS( PolyPolygon, NULL );
285 
286     if(nOptimizeFlags && Count())
287     {
288         // #115630# ImplDrawHatch does not work with beziers included in the polypolygon, take care of that
289         bool bIsCurve(false);
290 
291         for(sal_uInt16 a(0); !bIsCurve && a < Count(); a++)
292         {
293             if((*this)[a].HasFlags())
294             {
295                 bIsCurve = true;
296             }
297         }
298 
299         if(bIsCurve)
300         {
301             OSL_ENSURE(false, "Optimize does *not* support curves, falling back to AdaptiveSubdivide()...");
302             PolyPolygon aPolyPoly;
303 
304             AdaptiveSubdivide(aPolyPoly);
305             aPolyPoly.Optimize(nOptimizeFlags, pData);
306             *this = aPolyPoly;
307         }
308         else
309         {
310             double      fArea;
311             const sal_Bool  bEdges = ( nOptimizeFlags & POLY_OPTIMIZE_EDGES ) == POLY_OPTIMIZE_EDGES;
312             sal_uInt16      nPercent = 0;
313 
314             if( bEdges )
315             {
316                 const Rectangle aBound( GetBoundRect() );
317 
318                 fArea = ( aBound.GetWidth() + aBound.GetHeight() ) * 0.5;
319                 nPercent = pData ? pData->GetPercentValue() : 50;
320                 nOptimizeFlags &= ~POLY_OPTIMIZE_EDGES;
321             }
322 
323             // watch for ref counter
324             if( mpImplPolyPolygon->mnRefCount > 1 )
325             {
326                 mpImplPolyPolygon->mnRefCount--;
327                 mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
328             }
329 
330             // Optimize polygons
331             for( sal_uInt16 i = 0, nPolyCount = mpImplPolyPolygon->mnCount; i < nPolyCount; i++ )
332             {
333                 if( bEdges )
334                 {
335                     mpImplPolyPolygon->mpPolyAry[ i ]->Optimize( POLY_OPTIMIZE_NO_SAME );
336                     Polygon::ImplReduceEdges( *( mpImplPolyPolygon->mpPolyAry[ i ] ), fArea, nPercent );
337                 }
338 
339                 if( nOptimizeFlags )
340                     mpImplPolyPolygon->mpPolyAry[ i ]->Optimize( nOptimizeFlags, pData );
341             }
342         }
343     }
344 }
345 
346 // -----------------------------------------------------------------------
347 
AdaptiveSubdivide(PolyPolygon & rResult,const double d) const348 void PolyPolygon::AdaptiveSubdivide( PolyPolygon& rResult, const double d ) const
349 {
350     DBG_CHKTHIS( PolyPolygon, NULL );
351 
352     rResult.Clear();
353 
354     Polygon aPolygon;
355 
356     for( sal_uInt16 i = 0; i < mpImplPolyPolygon->mnCount; i++ )
357     {
358         mpImplPolyPolygon->mpPolyAry[ i ]->AdaptiveSubdivide( aPolygon, d );
359         rResult.Insert( aPolygon );
360     }
361 }
362 
363 // -----------------------------------------------------------------------
364 
GetIntersection(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const365 void PolyPolygon::GetIntersection( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
366 {
367     ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_INT );
368 }
369 
370 // -----------------------------------------------------------------------
371 
GetUnion(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const372 void PolyPolygon::GetUnion( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
373 {
374     ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_UNION );
375 }
376 
377 // -----------------------------------------------------------------------
378 
GetDifference(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const379 void PolyPolygon::GetDifference( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
380 {
381     ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_DIFF );
382 }
383 
384 // -----------------------------------------------------------------------
385 
GetXOR(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const386 void PolyPolygon::GetXOR( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
387 {
388     ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_XOR );
389 }
390 
391 // -----------------------------------------------------------------------
392 
ImplDoOperation(const PolyPolygon & rPolyPoly,PolyPolygon & rResult,sal_uIntPtr nOperation) const393 void PolyPolygon::ImplDoOperation( const PolyPolygon& rPolyPoly, PolyPolygon& rResult, sal_uIntPtr nOperation ) const
394 {
395     // Convert to B2DPolyPolygon, temporarily. It might be
396     // advantageous in the future, to have a PolyPolygon adaptor that
397     // just simulates a B2DPolyPolygon here...
398     basegfx::B2DPolyPolygon aMergePolyPolygonA( getB2DPolyPolygon() );
399     basegfx::B2DPolyPolygon aMergePolyPolygonB( rPolyPoly.getB2DPolyPolygon() );
400 
401     // normalize the two polypolygons before. Force properly oriented
402     // polygons.
403     aMergePolyPolygonA = basegfx::tools::prepareForPolygonOperation( aMergePolyPolygonA );
404     aMergePolyPolygonB = basegfx::tools::prepareForPolygonOperation( aMergePolyPolygonB );
405 
406     switch( nOperation )
407     {
408         // All code extracted from svx/source/svdraw/svedtv2.cxx
409         // -----------------------------------------------------
410 
411         case POLY_CLIP_UNION:
412         {
413             // merge A and B (OR)
414             aMergePolyPolygonA = basegfx::tools::solvePolygonOperationOr(aMergePolyPolygonA, aMergePolyPolygonB);
415             break;
416         }
417 
418         case POLY_CLIP_DIFF:
419         {
420             // substract B from A (DIFF)
421             aMergePolyPolygonA = basegfx::tools::solvePolygonOperationDiff(aMergePolyPolygonA, aMergePolyPolygonB);
422             break;
423         }
424 
425         case POLY_CLIP_XOR:
426         {
427             // compute XOR between poly A and B
428             aMergePolyPolygonA = basegfx::tools::solvePolygonOperationXor(aMergePolyPolygonA, aMergePolyPolygonB);
429             break;
430         }
431 
432         default:
433         case POLY_CLIP_INT:
434         {
435             // cut poly 1 against polys 2..n (AND)
436             aMergePolyPolygonA = basegfx::tools::solvePolygonOperationAnd(aMergePolyPolygonA, aMergePolyPolygonB);
437             break;
438         }
439     }
440 
441     rResult = PolyPolygon( aMergePolyPolygonA );
442 }
443 
444 // -----------------------------------------------------------------------
445 
Count() const446 sal_uInt16 PolyPolygon::Count() const
447 {
448     DBG_CHKTHIS( PolyPolygon, NULL );
449     return mpImplPolyPolygon->mnCount;
450 }
451 
452 // -----------------------------------------------------------------------
453 
Move(long nHorzMove,long nVertMove)454 void PolyPolygon::Move( long nHorzMove, long nVertMove )
455 {
456     DBG_CHKTHIS( PolyPolygon, NULL );
457 
458     // Diese Abfrage sollte man fuer die DrawEngine durchfuehren
459     if( nHorzMove || nVertMove )
460     {
461         // Referenzcounter beruecksichtigen
462         if ( mpImplPolyPolygon->mnRefCount > 1 )
463         {
464             mpImplPolyPolygon->mnRefCount--;
465             mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
466         }
467 
468         // Punkte verschieben
469         sal_uInt16 nPolyCount = mpImplPolyPolygon->mnCount;
470         for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
471             mpImplPolyPolygon->mpPolyAry[i]->Move( nHorzMove, nVertMove );
472     }
473 }
474 
475 // -----------------------------------------------------------------------
476 
Translate(const Point & rTrans)477 void PolyPolygon::Translate( const Point& rTrans )
478 {
479     DBG_CHKTHIS( PolyPolygon, NULL );
480 
481     // Referenzcounter beruecksichtigen
482     if( mpImplPolyPolygon->mnRefCount > 1 )
483     {
484         mpImplPolyPolygon->mnRefCount--;
485         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
486     }
487 
488     // Punkte verschieben
489     for ( sal_uInt16 i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
490         mpImplPolyPolygon->mpPolyAry[ i ]->Translate( rTrans );
491 }
492 
493 // -----------------------------------------------------------------------
494 
Scale(double fScaleX,double fScaleY)495 void PolyPolygon::Scale( double fScaleX, double fScaleY )
496 {
497     DBG_CHKTHIS( PolyPolygon, NULL );
498 
499     // Referenzcounter beruecksichtigen
500     if( mpImplPolyPolygon->mnRefCount > 1 )
501     {
502         mpImplPolyPolygon->mnRefCount--;
503         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
504     }
505 
506     // Punkte verschieben
507     for ( sal_uInt16 i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
508         mpImplPolyPolygon->mpPolyAry[ i ]->Scale( fScaleX, fScaleY );
509 }
510 
511 // -----------------------------------------------------------------------
512 
Rotate(const Point & rCenter,sal_uInt16 nAngle10)513 void PolyPolygon::Rotate( const Point& rCenter, sal_uInt16 nAngle10 )
514 {
515     DBG_CHKTHIS( PolyPolygon, NULL );
516     nAngle10 %= 3600;
517 
518     if( nAngle10 )
519     {
520         const double fAngle = F_PI1800 * nAngle10;
521         Rotate( rCenter, sin( fAngle ), cos( fAngle ) );
522     }
523 }
524 
525 // -----------------------------------------------------------------------
526 
Rotate(const Point & rCenter,double fSin,double fCos)527 void PolyPolygon::Rotate( const Point& rCenter, double fSin, double fCos )
528 {
529     DBG_CHKTHIS( PolyPolygon, NULL );
530 
531     // Referenzcounter beruecksichtigen
532     if( mpImplPolyPolygon->mnRefCount > 1 )
533     {
534         mpImplPolyPolygon->mnRefCount--;
535         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
536     }
537 
538     // Punkte verschieben
539     for ( sal_uInt16 i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
540         mpImplPolyPolygon->mpPolyAry[ i ]->Rotate( rCenter, fSin, fCos );
541 }
542 
543 // -----------------------------------------------------------------------
544 
SlantX(long nYRef,double fSin,double fCos)545 void PolyPolygon::SlantX( long nYRef, double fSin, double fCos )
546 {
547     DBG_CHKTHIS( PolyPolygon, NULL );
548 
549     // Referenzcounter beruecksichtigen
550     if( mpImplPolyPolygon->mnRefCount > 1 )
551     {
552         mpImplPolyPolygon->mnRefCount--;
553         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
554     }
555 
556     // Punkte verschieben
557     for ( sal_uInt16 i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
558         mpImplPolyPolygon->mpPolyAry[ i ]->SlantX( nYRef, fSin, fCos );
559 }
560 
561 // -----------------------------------------------------------------------
562 
SlantY(long nXRef,double fSin,double fCos)563 void PolyPolygon::SlantY( long nXRef, double fSin, double fCos )
564 {
565     DBG_CHKTHIS( PolyPolygon, NULL );
566 
567     // Referenzcounter beruecksichtigen
568     if( mpImplPolyPolygon->mnRefCount > 1 )
569     {
570         mpImplPolyPolygon->mnRefCount--;
571         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
572     }
573 
574     // Punkte verschieben
575     for ( sal_uInt16 i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
576         mpImplPolyPolygon->mpPolyAry[ i ]->SlantY( nXRef, fSin, fCos );
577 }
578 
579 // -----------------------------------------------------------------------
580 
Distort(const Rectangle & rRefRect,const Polygon & rDistortedRect)581 void PolyPolygon::Distort( const Rectangle& rRefRect, const Polygon& rDistortedRect )
582 {
583     DBG_CHKTHIS( PolyPolygon, NULL );
584 
585     // Referenzcounter beruecksichtigen
586     if( mpImplPolyPolygon->mnRefCount > 1 )
587     {
588         mpImplPolyPolygon->mnRefCount--;
589         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
590     }
591 
592     // Punkte verschieben
593     for ( sal_uInt16 i = 0, nCount = mpImplPolyPolygon->mnCount; i < nCount; i++ )
594         mpImplPolyPolygon->mpPolyAry[ i ]->Distort( rRefRect, rDistortedRect );
595 }
596 
597 
598 // -----------------------------------------------------------------------
599 
Clip(const Rectangle & rRect)600 void PolyPolygon::Clip( const Rectangle& rRect )
601 {
602     // Polygon-Clippen
603     sal_uInt16 nPolyCount = mpImplPolyPolygon->mnCount;
604     sal_uInt16 i;
605 
606     if ( !nPolyCount )
607         return;
608 
609     // Referenzcounter beruecksichtigen
610     if ( mpImplPolyPolygon->mnRefCount > 1 )
611     {
612         mpImplPolyPolygon->mnRefCount--;
613         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
614     }
615 
616     // Erst jedes Polygon Clippen und dann die leeren entfernen
617     for ( i = 0; i < nPolyCount; i++ )
618         mpImplPolyPolygon->mpPolyAry[i]->Clip( rRect );
619     while ( nPolyCount )
620     {
621         if ( GetObject( nPolyCount-1 ).GetSize() <= 2 )
622             Remove( nPolyCount-1 );
623         nPolyCount--;
624     }
625 }
626 
627 // -----------------------------------------------------------------------
628 
GetBoundRect() const629 Rectangle PolyPolygon::GetBoundRect() const
630 {
631     DBG_CHKTHIS( PolyPolygon, NULL );
632 
633     long    nXMin=0, nXMax=0, nYMin=0, nYMax=0;
634     sal_Bool    bFirst = sal_True;
635     sal_uInt16  nPolyCount = mpImplPolyPolygon->mnCount;
636 
637     for ( sal_uInt16 n = 0; n < nPolyCount; n++ )
638     {
639         const Polygon*  pPoly = mpImplPolyPolygon->mpPolyAry[n];
640         const Point*    pAry = pPoly->GetConstPointAry();
641         sal_uInt16          nPointCount = pPoly->GetSize();
642 
643         for ( sal_uInt16 i = 0; i < nPointCount; i++ )
644         {
645             const Point* pPt = &pAry[ i ];
646 
647             if ( bFirst )
648             {
649                 nXMin = nXMax = pPt->X();
650                 nYMin = nYMax = pPt->Y();
651                 bFirst = sal_False;
652             }
653             else
654             {
655                 if ( pPt->X() < nXMin )
656                     nXMin = pPt->X();
657                 if ( pPt->X() > nXMax )
658                     nXMax = pPt->X();
659                 if ( pPt->Y() < nYMin )
660                     nYMin = pPt->Y();
661                 if ( pPt->Y() > nYMax )
662                     nYMax = pPt->Y();
663             }
664         }
665     }
666 
667     if ( !bFirst )
668         return Rectangle( nXMin, nYMin, nXMax, nYMax );
669     else
670         return Rectangle();
671 }
672 
673 // -----------------------------------------------------------------------
674 
operator [](sal_uInt16 nPos)675 Polygon& PolyPolygon::operator[]( sal_uInt16 nPos )
676 {
677     DBG_CHKTHIS( PolyPolygon, NULL );
678     DBG_ASSERT( nPos < Count(), "PolyPolygon::[](): nPos >= nSize" );
679 
680     if ( mpImplPolyPolygon->mnRefCount > 1 )
681     {
682         mpImplPolyPolygon->mnRefCount--;
683         mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
684     }
685 
686     return *(mpImplPolyPolygon->mpPolyAry[nPos]);
687 }
688 
689 // -----------------------------------------------------------------------
690 
operator =(const PolyPolygon & rPolyPoly)691 PolyPolygon& PolyPolygon::operator=( const PolyPolygon& rPolyPoly )
692 {
693     DBG_CHKTHIS( PolyPolygon, NULL );
694     DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
695     DBG_ASSERT( rPolyPoly.mpImplPolyPolygon->mnRefCount < 0xFFFFFFFE, "PolyPolygon: RefCount overflow" );
696 
697     rPolyPoly.mpImplPolyPolygon->mnRefCount++;
698 
699     if ( mpImplPolyPolygon->mnRefCount > 1 )
700         mpImplPolyPolygon->mnRefCount--;
701     else
702         delete mpImplPolyPolygon;
703 
704     mpImplPolyPolygon = rPolyPoly.mpImplPolyPolygon;
705     return *this;
706 }
707 
708 // -----------------------------------------------------------------------
709 
operator ==(const PolyPolygon & rPolyPoly) const710 sal_Bool PolyPolygon::operator==( const PolyPolygon& rPolyPoly ) const
711 {
712     DBG_CHKTHIS( PolyPolygon, NULL );
713     DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
714 
715     if ( rPolyPoly.mpImplPolyPolygon == mpImplPolyPolygon )
716         return sal_True;
717     else
718         return sal_False;
719 }
720 
721 // -----------------------------------------------------------------------
722 
IsEqual(const PolyPolygon & rPolyPoly) const723 sal_Bool PolyPolygon::IsEqual( const PolyPolygon& rPolyPoly ) const
724 {
725     sal_Bool bIsEqual = sal_True;
726     if ( Count() != rPolyPoly.Count() )
727         bIsEqual = sal_False;
728     else
729     {
730         sal_uInt16 i;
731         for ( i = 0; i < Count(); i++ )
732         {
733             if (!GetObject( i ).IsEqual( rPolyPoly.GetObject( i ) ) )
734             {
735                 bIsEqual = sal_False;
736                 break;
737             }
738         }
739     }
740     return bIsEqual;
741 }
742 
743 // -----------------------------------------------------------------------
744 
operator >>(SvStream & rIStream,PolyPolygon & rPolyPoly)745 SvStream& operator>>( SvStream& rIStream, PolyPolygon& rPolyPoly )
746 {
747     DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
748     DBG_ASSERTWARNING( rIStream.GetVersion(), "PolyPolygon::>> - Solar-Version not set on rIStream" );
749 
750     Polygon* pPoly;
751     sal_uInt16   nPolyCount;
752 
753     // Anzahl der Polygone einlesen
754     rIStream >> nPolyCount;
755 
756     // Daten anlegen
757     if( nPolyCount )
758     {
759         // Referenzcounter beruecksichtigen
760         if ( rPolyPoly.mpImplPolyPolygon->mnRefCount > 1 )
761             rPolyPoly.mpImplPolyPolygon->mnRefCount--;
762         else
763             delete rPolyPoly.mpImplPolyPolygon;
764 
765         rPolyPoly.mpImplPolyPolygon = new ImplPolyPolygon( nPolyCount );
766 
767         for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
768         {
769             pPoly = new Polygon;
770             rIStream >> *pPoly;
771             rPolyPoly.mpImplPolyPolygon->mpPolyAry[i] = pPoly;
772         }
773     }
774     else
775         rPolyPoly = PolyPolygon();
776 
777     return rIStream;
778 }
779 
780 // -----------------------------------------------------------------------
781 
operator <<(SvStream & rOStream,const PolyPolygon & rPolyPoly)782 SvStream& operator<<( SvStream& rOStream, const PolyPolygon& rPolyPoly )
783 {
784     DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
785     DBG_ASSERTWARNING( rOStream.GetVersion(), "PolyPolygon::<< - Solar-Version not set on rOStream" );
786 
787     // Anzahl der Polygone rausschreiben
788     sal_uInt16 nPolyCount = rPolyPoly.mpImplPolyPolygon->mnCount;
789     rOStream << nPolyCount;
790 
791     // Die einzelnen Polygone ausgeben
792     for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
793         rOStream << *(rPolyPoly.mpImplPolyPolygon->mpPolyAry[i]);
794 
795     return rOStream;
796 }
797 
798 // -----------------------------------------------------------------------
799 
Read(SvStream & rIStream)800 void PolyPolygon::Read( SvStream& rIStream )
801 {
802     VersionCompat aCompat( rIStream, STREAM_READ );
803 
804     DBG_CHKTHIS( PolyPolygon, NULL );
805     DBG_ASSERTWARNING( rIStream.GetVersion(), "PolyPolygon::>> - Solar-Version not set on rIStream" );
806 
807     Polygon* pPoly;
808     sal_uInt16   nPolyCount;
809 
810     // Anzahl der Polygone einlesen
811     rIStream >> nPolyCount;
812 
813     // Daten anlegen
814     if( nPolyCount )
815     {
816         // Referenzcounter beruecksichtigen
817         if ( mpImplPolyPolygon->mnRefCount > 1 )
818             mpImplPolyPolygon->mnRefCount--;
819         else
820             delete mpImplPolyPolygon;
821 
822         mpImplPolyPolygon = new ImplPolyPolygon( nPolyCount );
823 
824         for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
825         {
826             pPoly = new Polygon;
827             pPoly->ImplRead( rIStream );
828             mpImplPolyPolygon->mpPolyAry[i] = pPoly;
829         }
830     }
831     else
832         *this = PolyPolygon();
833 }
834 
835 // -----------------------------------------------------------------------
836 
Write(SvStream & rOStream) const837 void PolyPolygon::Write( SvStream& rOStream ) const
838 {
839     VersionCompat aCompat( rOStream, STREAM_WRITE, 1 );
840 
841     DBG_CHKTHIS( PolyPolygon, NULL );
842     DBG_ASSERTWARNING( rOStream.GetVersion(), "PolyPolygon::<< - Solar-Version not set on rOStream" );
843 
844     // Anzahl der Polygone rausschreiben
845     sal_uInt16 nPolyCount = mpImplPolyPolygon->mnCount;
846     rOStream << nPolyCount;
847 
848     // Die einzelnen Polygone ausgeben
849     for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
850         mpImplPolyPolygon->mpPolyAry[i]->ImplWrite( rOStream );;
851 }
852 
853 // -----------------------------------------------------------------------
854 // convert to basegfx::B2DPolyPolygon and return
getB2DPolyPolygon() const855 basegfx::B2DPolyPolygon PolyPolygon::getB2DPolyPolygon() const
856 {
857     basegfx::B2DPolyPolygon aRetval;
858 
859     for(sal_uInt16 a(0); a < mpImplPolyPolygon->mnCount; a++)
860     {
861         Polygon* pCandidate = mpImplPolyPolygon->mpPolyAry[a];
862         aRetval.append(pCandidate->getB2DPolygon());
863     }
864 
865     return aRetval;
866 }
867 
868 // -----------------------------------------------------------------------
869 // constructor to convert from basegfx::B2DPolyPolygon
PolyPolygon(const basegfx::B2DPolyPolygon & rPolyPolygon)870 PolyPolygon::PolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon)
871 {
872     DBG_CTOR( PolyPolygon, NULL );
873     const sal_uInt16 nCount(sal_uInt16(rPolyPolygon.count()));
874     DBG_ASSERT(sal_uInt32(nCount) == rPolyPolygon.count(),
875         "PolyPolygon::PolyPolygon: Too many sub-polygons in given basegfx::B2DPolyPolygon (!)");
876 
877     if ( nCount )
878     {
879         mpImplPolyPolygon = new ImplPolyPolygon( nCount );
880 
881         for(sal_uInt16 a(0); a < nCount; a++)
882         {
883             basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(sal_uInt32(a)));
884             mpImplPolyPolygon->mpPolyAry[a] = new Polygon( aCandidate );
885         }
886     }
887     else
888     {
889         mpImplPolyPolygon = new ImplPolyPolygon( 16, 16 );
890     }
891 }
892 
893 // eof
894