xref: /trunk/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