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