xref: /aoo42x/main/tools/source/generic/poly2.cxx (revision 09b5452f)
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 	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 
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 
236 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 
246 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 
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 
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 
348 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 
365 void PolyPolygon::GetIntersection( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
366 {
367 	ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_INT );
368 }
369 
370 // -----------------------------------------------------------------------
371 
372 void PolyPolygon::GetUnion( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
373 {
374 	ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_UNION );
375 }
376 
377 // -----------------------------------------------------------------------
378 
379 void PolyPolygon::GetDifference( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
380 {
381 	ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_DIFF );
382 }
383 
384 // -----------------------------------------------------------------------
385 
386 void PolyPolygon::GetXOR( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
387 {
388 	ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_XOR );
389 }
390 
391 // -----------------------------------------------------------------------
392 
393 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 			// subtract 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 
446 sal_uInt16 PolyPolygon::Count() const
447 {
448 	DBG_CHKTHIS( PolyPolygon, NULL );
449 	return mpImplPolyPolygon->mnCount;
450 }
451 
452 // -----------------------------------------------------------------------
453 
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 
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 
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 
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 
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 
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 
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 
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 
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 
629 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 
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 
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 
710 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 
723 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 
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 
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 
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 
837 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
855 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
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