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