xref: /aoo41x/main/tools/source/generic/poly2.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_tools.hxx"
30 
31 #define _SV_POLY2_CXX
32 
33 #define POLY_CLIP_INT   0
34 #define POLY_CLIP_UNION 1
35 #define POLY_CLIP_DIFF  2
36 #define POLY_CLIP_XOR   3
37 
38 #include <rtl/math.hxx>
39 #include <poly.h>
40 #include <tools/poly.hxx>
41 #include <tools/debug.hxx>
42 #include <tools/stream.hxx>
43 #include <tools/vcompat.hxx>
44 #include <basegfx/polygon/b2dpolypolygon.hxx>
45 #include <basegfx/polygon/b2dpolygon.hxx>
46 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
47 
48 // ---------------
49 // - PolyPolygon -
50 // ---------------
51 
52 DBG_NAME( PolyPolygon )
53 
54 // -----------------------------------------------------------------------
55 
56 ImplPolyPolygon::ImplPolyPolygon( sal_uInt16 nInitSize )
57 {
58 	mnRefCount	= 1;
59 	mnCount 	= nInitSize;
60 	mnSize		= nInitSize;
61 	mnResize	= 16;
62 	mpPolyAry	= new SVPPOLYGON[ nInitSize ];
63 }
64 
65 // -----------------------------------------------------------------------
66 
67 ImplPolyPolygon::ImplPolyPolygon( const ImplPolyPolygon& rImplPolyPoly )
68 {
69 	mnRefCount	= 1;
70 	mnCount 	= rImplPolyPoly.mnCount;
71 	mnSize		= rImplPolyPoly.mnSize;
72 	mnResize	= rImplPolyPoly.mnResize;
73 
74 	if ( rImplPolyPoly.mpPolyAry )
75 	{
76 		mpPolyAry = new SVPPOLYGON[mnSize];
77 		for ( sal_uInt16 i = 0; i < mnCount; i++ )
78 			mpPolyAry[i] = new Polygon( *rImplPolyPoly.mpPolyAry[i] );
79 	}
80 	else
81 		mpPolyAry = NULL;
82 }
83 
84 // -----------------------------------------------------------------------
85 
86 ImplPolyPolygon::~ImplPolyPolygon()
87 {
88 	if ( mpPolyAry )
89 	{
90 		for ( sal_uInt16 i = 0; i < mnCount; i++ )
91 			delete mpPolyAry[i];
92 		delete[] mpPolyAry;
93 	}
94 }
95 
96 // =======================================================================
97 
98 PolyPolygon::PolyPolygon( sal_uInt16 nInitSize, sal_uInt16 nResize )
99 {
100 	DBG_CTOR( PolyPolygon, NULL );
101 
102 	if ( nInitSize > MAX_POLYGONS )
103 		nInitSize = MAX_POLYGONS;
104 	else if ( !nInitSize )
105 		nInitSize = 1;
106 	if ( nResize > MAX_POLYGONS )
107 		nResize = MAX_POLYGONS;
108 	else if ( !nResize )
109 		nResize = 1;
110 	mpImplPolyPolygon = new ImplPolyPolygon( nInitSize, nResize );
111 }
112 
113 // -----------------------------------------------------------------------
114 
115 PolyPolygon::PolyPolygon( const Polygon& rPoly )
116 {
117 	DBG_CTOR( PolyPolygon, NULL );
118 
119 	if ( rPoly.GetSize() )
120 	{
121 		mpImplPolyPolygon = new ImplPolyPolygon( 1 );
122 		mpImplPolyPolygon->mpPolyAry[0] = new Polygon( rPoly );
123 	}
124 	else
125 		mpImplPolyPolygon = new ImplPolyPolygon( 16, 16 );
126 }
127 
128 // -----------------------------------------------------------------------
129 
130 PolyPolygon::PolyPolygon( sal_uInt16 nPoly, const sal_uInt16* pPointCountAry,
131 						  const Point* pPtAry )
132 {
133 	DBG_CTOR( PolyPolygon, NULL );
134 
135 	if ( nPoly > MAX_POLYGONS )
136 		nPoly = MAX_POLYGONS;
137 
138 	mpImplPolyPolygon = new ImplPolyPolygon( nPoly );
139 	for ( sal_uInt16 i = 0; i < nPoly; i++ )
140 	{
141 		mpImplPolyPolygon->mpPolyAry[i] = new Polygon( *pPointCountAry, pPtAry );
142 		pPtAry += *pPointCountAry;
143 		pPointCountAry++;
144 	}
145 }
146 
147 // -----------------------------------------------------------------------
148 
149 PolyPolygon::PolyPolygon( const PolyPolygon& rPolyPoly )
150 {
151 	DBG_CTOR( PolyPolygon, NULL );
152 	DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
153 	DBG_ASSERT( rPolyPoly.mpImplPolyPolygon->mnRefCount < 0xFFFFFFFE, "PolyPolygon: RefCount overflow" );
154 
155 	mpImplPolyPolygon = rPolyPoly.mpImplPolyPolygon;
156 	mpImplPolyPolygon->mnRefCount++;
157 }
158 
159 // -----------------------------------------------------------------------
160 
161 PolyPolygon::~PolyPolygon()
162 {
163 	DBG_DTOR( PolyPolygon, NULL );
164 
165 	if ( mpImplPolyPolygon->mnRefCount > 1 )
166 		mpImplPolyPolygon->mnRefCount--;
167 	else
168 		delete mpImplPolyPolygon;
169 }
170 
171 // -----------------------------------------------------------------------
172 
173 void PolyPolygon::Insert( const Polygon& rPoly, sal_uInt16 nPos )
174 {
175 	DBG_CHKTHIS( PolyPolygon, NULL );
176 
177 	if ( mpImplPolyPolygon->mnCount >= MAX_POLYGONS )
178 		return;
179 
180 	if ( mpImplPolyPolygon->mnRefCount > 1 )
181 	{
182 		mpImplPolyPolygon->mnRefCount--;
183 		mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
184 	}
185 
186 	if ( nPos > mpImplPolyPolygon->mnCount )
187 		nPos = mpImplPolyPolygon->mnCount;
188 
189 	if ( !mpImplPolyPolygon->mpPolyAry )
190 		mpImplPolyPolygon->mpPolyAry = new SVPPOLYGON[mpImplPolyPolygon->mnSize];
191 	else if ( mpImplPolyPolygon->mnCount == mpImplPolyPolygon->mnSize )
192 	{
193 		sal_uInt16		nOldSize = mpImplPolyPolygon->mnSize;
194 		sal_uInt16		nNewSize = nOldSize + mpImplPolyPolygon->mnResize;
195 		SVPPOLYGON* pNewAry;
196 
197 		if ( nNewSize >= MAX_POLYGONS )
198 			nNewSize = MAX_POLYGONS;
199 		pNewAry = new SVPPOLYGON[nNewSize];
200 		memcpy( pNewAry, mpImplPolyPolygon->mpPolyAry, nPos*sizeof(SVPPOLYGON) );
201 		memcpy( pNewAry+nPos+1, mpImplPolyPolygon->mpPolyAry+nPos,
202 				(nOldSize-nPos)*sizeof(SVPPOLYGON) );
203 		delete[] mpImplPolyPolygon->mpPolyAry;
204 		mpImplPolyPolygon->mpPolyAry = pNewAry;
205 		mpImplPolyPolygon->mnSize = nNewSize;
206 	}
207 	else if ( nPos < mpImplPolyPolygon->mnCount )
208 	{
209 		memmove( mpImplPolyPolygon->mpPolyAry+nPos+1,
210 				 mpImplPolyPolygon->mpPolyAry+nPos,
211 				 (mpImplPolyPolygon->mnCount-nPos)*sizeof(SVPPOLYGON) );
212 	}
213 
214 	mpImplPolyPolygon->mpPolyAry[nPos] = new Polygon( rPoly );
215 	mpImplPolyPolygon->mnCount++;
216 }
217 
218 // -----------------------------------------------------------------------
219 
220 void PolyPolygon::Remove( sal_uInt16 nPos )
221 {
222 	DBG_CHKTHIS( PolyPolygon, NULL );
223 	DBG_ASSERT( nPos < Count(), "PolyPolygon::Remove(): nPos >= nSize" );
224 
225 	if ( mpImplPolyPolygon->mnRefCount > 1 )
226 	{
227 		mpImplPolyPolygon->mnRefCount--;
228 		mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
229 	}
230 
231 	delete mpImplPolyPolygon->mpPolyAry[nPos];
232 	mpImplPolyPolygon->mnCount--;
233 	memmove( mpImplPolyPolygon->mpPolyAry+nPos,
234 			 mpImplPolyPolygon->mpPolyAry+nPos+1,
235 			 (mpImplPolyPolygon->mnCount-nPos)*sizeof(SVPPOLYGON) );
236 }
237 
238 // -----------------------------------------------------------------------
239 
240 void PolyPolygon::Replace( const Polygon& rPoly, sal_uInt16 nPos )
241 {
242 	DBG_CHKTHIS( PolyPolygon, NULL );
243 	DBG_ASSERT( nPos < Count(), "PolyPolygon::Replace(): nPos >= nSize" );
244 
245 	if ( mpImplPolyPolygon->mnRefCount > 1 )
246 	{
247 		mpImplPolyPolygon->mnRefCount--;
248 		mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
249 	}
250 
251 	delete mpImplPolyPolygon->mpPolyAry[nPos];
252 	mpImplPolyPolygon->mpPolyAry[nPos] = new Polygon( rPoly );
253 }
254 
255 // -----------------------------------------------------------------------
256 
257 const Polygon& PolyPolygon::GetObject( sal_uInt16 nPos ) const
258 {
259 	DBG_CHKTHIS( PolyPolygon, NULL );
260 	DBG_ASSERT( nPos < Count(), "PolyPolygon::GetObject(): nPos >= nSize" );
261 
262 	return *(mpImplPolyPolygon->mpPolyAry[nPos]);
263 }
264 
265 // -----------------------------------------------------------------------
266 
267 sal_Bool PolyPolygon::IsRect() const
268 {
269 	sal_Bool bIsRect = sal_False;
270 	if ( Count() == 1 )
271 		bIsRect = mpImplPolyPolygon->mpPolyAry[ 0 ]->IsRect();
272 	return bIsRect;
273 }
274 
275 // -----------------------------------------------------------------------
276 
277 void PolyPolygon::Clear()
278 {
279 	DBG_CHKTHIS( PolyPolygon, NULL );
280 
281 	if ( mpImplPolyPolygon->mnRefCount > 1 )
282 	{
283 		mpImplPolyPolygon->mnRefCount--;
284 		mpImplPolyPolygon = new ImplPolyPolygon( mpImplPolyPolygon->mnResize,
285 												 mpImplPolyPolygon->mnResize );
286 	}
287 	else
288 	{
289 		if ( mpImplPolyPolygon->mpPolyAry )
290 		{
291 			for ( sal_uInt16 i = 0; i < mpImplPolyPolygon->mnCount; i++ )
292 				delete mpImplPolyPolygon->mpPolyAry[i];
293 			delete[] mpImplPolyPolygon->mpPolyAry;
294 			mpImplPolyPolygon->mpPolyAry = NULL;
295 			mpImplPolyPolygon->mnCount	 = 0;
296 			mpImplPolyPolygon->mnSize	 = mpImplPolyPolygon->mnResize;
297 		}
298 	}
299 }
300 
301 // -----------------------------------------------------------------------
302 
303 void PolyPolygon::Optimize( sal_uIntPtr nOptimizeFlags, const PolyOptimizeData* pData )
304 {
305 	DBG_CHKTHIS( PolyPolygon, NULL );
306 
307 	if( nOptimizeFlags )
308 	{
309 		double		fArea;
310 		const sal_Bool	bEdges = ( nOptimizeFlags & POLY_OPTIMIZE_EDGES ) == POLY_OPTIMIZE_EDGES;
311 		sal_uInt16		nPercent = 0;
312 
313 		if( bEdges )
314 		{
315 			const Rectangle aBound( GetBoundRect() );
316 
317 			fArea = ( aBound.GetWidth() + aBound.GetHeight() ) * 0.5;
318 			nPercent = pData ? pData->GetPercentValue() : 50;
319 			nOptimizeFlags &= ~POLY_OPTIMIZE_EDGES;
320 		}
321 
322 		// watch for ref counter
323 		if( mpImplPolyPolygon->mnRefCount > 1 )
324 		{
325 			mpImplPolyPolygon->mnRefCount--;
326 			mpImplPolyPolygon = new ImplPolyPolygon( *mpImplPolyPolygon );
327 		}
328 
329 		// Optimize polygons
330 		for( sal_uInt16 i = 0, nPolyCount = mpImplPolyPolygon->mnCount; i < nPolyCount; i++ )
331 		{
332 			if( bEdges )
333 			{
334 				mpImplPolyPolygon->mpPolyAry[ i ]->Optimize( POLY_OPTIMIZE_NO_SAME );
335 				Polygon::ImplReduceEdges( *( mpImplPolyPolygon->mpPolyAry[ i ] ), fArea, nPercent );
336 			}
337 
338 			if( nOptimizeFlags )
339 				mpImplPolyPolygon->mpPolyAry[ i ]->Optimize( nOptimizeFlags, pData );
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             // substract 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