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
DBG_NAME(PolyPolygon)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
ImplPolyPolygon(const ImplPolyPolygon & rImplPolyPoly)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
~ImplPolyPolygon()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
PolyPolygon(sal_uInt16 nInitSize,sal_uInt16 nResize)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
PolyPolygon(const Polygon & rPoly)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
PolyPolygon(const PolyPolygon & rPolyPoly)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
~PolyPolygon()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
Insert(const Polygon & rPoly,sal_uInt16 nPos)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
Remove(sal_uInt16 nPos)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
Replace(const Polygon & rPoly,sal_uInt16 nPos)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
GetObject(sal_uInt16 nPos) const236 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
IsRect() const246 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
Clear()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
Optimize(sal_uIntPtr nOptimizeFlags,const PolyOptimizeData * pData)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
AdaptiveSubdivide(PolyPolygon & rResult,const double d) const348 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
GetIntersection(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const365 void PolyPolygon::GetIntersection( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
366 {
367 ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_INT );
368 }
369
370 // -----------------------------------------------------------------------
371
GetUnion(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const372 void PolyPolygon::GetUnion( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
373 {
374 ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_UNION );
375 }
376
377 // -----------------------------------------------------------------------
378
GetDifference(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const379 void PolyPolygon::GetDifference( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
380 {
381 ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_DIFF );
382 }
383
384 // -----------------------------------------------------------------------
385
GetXOR(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const386 void PolyPolygon::GetXOR( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
387 {
388 ImplDoOperation( rPolyPoly, rResult, POLY_CLIP_XOR );
389 }
390
391 // -----------------------------------------------------------------------
392
ImplDoOperation(const PolyPolygon & rPolyPoly,PolyPolygon & rResult,sal_uIntPtr nOperation) const393 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
Count() const446 sal_uInt16 PolyPolygon::Count() const
447 {
448 DBG_CHKTHIS( PolyPolygon, NULL );
449 return mpImplPolyPolygon->mnCount;
450 }
451
452 // -----------------------------------------------------------------------
453
Move(long nHorzMove,long nVertMove)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
Translate(const Point & rTrans)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
Scale(double fScaleX,double fScaleY)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
Rotate(const Point & rCenter,sal_uInt16 nAngle10)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
Rotate(const Point & rCenter,double fSin,double fCos)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
SlantX(long nYRef,double fSin,double fCos)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
SlantY(long nXRef,double fSin,double fCos)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
Distort(const Rectangle & rRefRect,const Polygon & rDistortedRect)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
Clip(const Rectangle & rRect)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
GetBoundRect() const629 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
operator [](sal_uInt16 nPos)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
operator =(const PolyPolygon & rPolyPoly)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
operator ==(const PolyPolygon & rPolyPoly) const710 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
IsEqual(const PolyPolygon & rPolyPoly) const723 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
operator >>(SvStream & rIStream,PolyPolygon & rPolyPoly)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
operator <<(SvStream & rOStream,const PolyPolygon & rPolyPoly)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
Read(SvStream & rIStream)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
Write(SvStream & rOStream) const837 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
getB2DPolyPolygon() const855 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
PolyPolygon(const basegfx::B2DPolyPolygon & rPolyPolygon)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 /* vim: set noet sw=4 ts=4: */
894