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