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_POLY_CXX
28 #include <osl/endian.h>
29 #include <tools/bigint.hxx>
30 #include <tools/debug.hxx>
31 #include <tools/stream.hxx>
32 #include <tools/vcompat.hxx>
33 #include <poly.h>
34 #include <tools/line.hxx>
35 #ifndef _VECTOR2D_H
36 #include <tools/vector2d.hxx>
37 #endif
38 #ifndef _POLY_HXX
39 #include <tools/poly.hxx>
40 #endif
41 #include <basegfx/polygon/b2dpolygon.hxx>
42 #include <basegfx/point/b2dpoint.hxx>
43 #include <basegfx/vector/b2dvector.hxx>
44 #include <basegfx/polygon/b2dpolygontools.hxx>
45 #include <basegfx/curve/b2dcubicbezier.hxx>
46
47 #include <vector>
48 #include <iterator>
49 #include <algorithm>
50 #include <cstring>
51 #include <limits.h>
52 #include <cmath>
53
54
55 // =======================================================================
56
57 DBG_NAME( Polygon )
58
59 // -----------------------------------------------------------------------
60
61 #define EDGE_LEFT 1
62 #define EDGE_TOP 2
63 #define EDGE_RIGHT 4
64 #define EDGE_BOTTOM 8
65 #define EDGE_HORZ (EDGE_RIGHT | EDGE_LEFT)
66 #define EDGE_VERT (EDGE_TOP | EDGE_BOTTOM)
67 #define SMALL_DVALUE 0.0000001
68 #define FSQRT2 1.4142135623730950488016887242097
69
70 // -----------------------------------------------------------------------
71
72 static ImplPolygonData aStaticImplPolygon =
73 {
74 NULL, NULL, 0, 0
75 };
76
77 // =======================================================================
78
ImplPolygon(sal_uInt16 nInitSize,sal_Bool bFlags)79 ImplPolygon::ImplPolygon( sal_uInt16 nInitSize, sal_Bool bFlags )
80 {
81 if ( nInitSize )
82 {
83 mpPointAry = (Point*)new char[(sal_uIntPtr)nInitSize*sizeof(Point)];
84 memset( mpPointAry, 0, (sal_uIntPtr)nInitSize*sizeof(Point) );
85 }
86 else
87 mpPointAry = NULL;
88
89 if( bFlags )
90 {
91 mpFlagAry = new sal_uInt8[ nInitSize ];
92 memset( mpPointAry, 0, nInitSize );
93 }
94 else
95 mpFlagAry = NULL;
96
97 mnRefCount = 1;
98 mnPoints = nInitSize;
99 }
100
101 // -----------------------------------------------------------------------
102
ImplPolygon(const ImplPolygon & rImpPoly)103 ImplPolygon::ImplPolygon( const ImplPolygon& rImpPoly )
104 {
105 if ( rImpPoly.mnPoints )
106 {
107 mpPointAry = (Point*)new char[(sal_uIntPtr)rImpPoly.mnPoints*sizeof(Point)];
108 memcpy( mpPointAry, rImpPoly.mpPointAry, (sal_uIntPtr)rImpPoly.mnPoints*sizeof(Point) );
109
110 if( rImpPoly.mpFlagAry )
111 {
112 mpFlagAry = new sal_uInt8[ rImpPoly.mnPoints ];
113 memcpy( mpFlagAry, rImpPoly.mpFlagAry, rImpPoly.mnPoints );
114 }
115 else
116 mpFlagAry = NULL;
117 }
118 else
119 {
120 mpPointAry = NULL;
121 mpFlagAry = NULL;
122 }
123
124 mnRefCount = 1;
125 mnPoints = rImpPoly.mnPoints;
126 }
127
128 // -----------------------------------------------------------------------
129
ImplPolygon(sal_uInt16 nInitSize,const Point * pInitAry,const sal_uInt8 * pInitFlags)130 ImplPolygon::ImplPolygon( sal_uInt16 nInitSize, const Point* pInitAry, const sal_uInt8* pInitFlags )
131 {
132 if ( nInitSize )
133 {
134 mpPointAry = (Point*)new char[(sal_uIntPtr)nInitSize*sizeof(Point)];
135 memcpy( mpPointAry, pInitAry, (sal_uIntPtr)nInitSize*sizeof( Point ) );
136
137 if( pInitFlags )
138 {
139 mpFlagAry = new sal_uInt8[ nInitSize ];
140 memcpy( mpFlagAry, pInitFlags, nInitSize );
141 }
142 else
143 mpFlagAry = NULL;
144 }
145 else
146 {
147 mpPointAry = NULL;
148 mpFlagAry = NULL;
149 }
150
151 mnRefCount = 1;
152 mnPoints = nInitSize;
153 }
154
155 // -----------------------------------------------------------------------
156
~ImplPolygon()157 ImplPolygon::~ImplPolygon()
158 {
159 if ( mpPointAry )
160 {
161 delete[] (char*) mpPointAry;
162 }
163
164 if( mpFlagAry )
165 delete[] mpFlagAry;
166 }
167
168 // -----------------------------------------------------------------------
169
ImplSetSize(sal_uInt16 nNewSize,sal_Bool bResize)170 void ImplPolygon::ImplSetSize( sal_uInt16 nNewSize, sal_Bool bResize )
171 {
172 if( mnPoints == nNewSize )
173 return;
174
175 Point* pNewAry;
176
177 if ( nNewSize )
178 {
179 pNewAry = (Point*)new char[(sal_uIntPtr)nNewSize*sizeof(Point)];
180
181 if ( bResize )
182 {
183 // Alte Punkte kopieren
184 if ( mnPoints < nNewSize )
185 {
186 // Neue Punkte mit 0 initialisieren
187 memset( pNewAry+mnPoints, 0, (sal_uIntPtr)(nNewSize-mnPoints)*sizeof(Point) );
188 if ( mpPointAry )
189 memcpy( pNewAry, mpPointAry, mnPoints*sizeof(Point) );
190 }
191 else
192 {
193 if ( mpPointAry )
194 memcpy( pNewAry, mpPointAry, (sal_uIntPtr)nNewSize*sizeof(Point) );
195 }
196 }
197 }
198 else
199 pNewAry = NULL;
200
201 if ( mpPointAry )
202 delete[] (char*) mpPointAry;
203
204 // ggf. FlagArray beruecksichtigen
205 if( mpFlagAry )
206 {
207 sal_uInt8* pNewFlagAry;
208
209 if( nNewSize )
210 {
211 pNewFlagAry = new sal_uInt8[ nNewSize ];
212
213 if( bResize )
214 {
215 // Alte Flags kopieren
216 if ( mnPoints < nNewSize )
217 {
218 // Neue Punkte mit 0 initialisieren
219 memset( pNewFlagAry+mnPoints, 0, nNewSize-mnPoints );
220 memcpy( pNewFlagAry, mpFlagAry, mnPoints );
221 }
222 else
223 memcpy( pNewFlagAry, mpFlagAry, nNewSize );
224 }
225 }
226 else
227 pNewFlagAry = NULL;
228
229 delete[] mpFlagAry;
230 mpFlagAry = pNewFlagAry;
231 }
232
233 mpPointAry = pNewAry;
234 mnPoints = nNewSize;
235 }
236
237 // -----------------------------------------------------------------------
238
ImplSplit(sal_uInt16 nPos,sal_uInt16 nSpace,ImplPolygon * pInitPoly)239 void ImplPolygon::ImplSplit( sal_uInt16 nPos, sal_uInt16 nSpace, ImplPolygon* pInitPoly )
240 {
241 const sal_uIntPtr nSpaceSize = nSpace * sizeof( Point );
242
243 //Can't fit this in :-(, throw ?
244 if (mnPoints + nSpace > USHRT_MAX)
245 return;
246
247 const sal_uInt16 nNewSize = mnPoints + nSpace;
248
249 if( nPos >= mnPoints )
250 {
251 // Hinten anhaengen
252 nPos = mnPoints;
253 ImplSetSize( nNewSize, sal_True );
254
255 if( pInitPoly )
256 {
257 memcpy( mpPointAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
258
259 if( pInitPoly->mpFlagAry )
260 memcpy( mpFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
261 }
262 }
263 else
264 {
265 // PointArray ist in diesem Zweig immer vorhanden
266 const sal_uInt16 nSecPos = nPos + nSpace;
267 const sal_uInt16 nRest = mnPoints - nPos;
268
269 Point* pNewAry = (Point*) new char[ (sal_uIntPtr) nNewSize * sizeof( Point ) ];
270
271 memcpy( pNewAry, mpPointAry, nPos * sizeof( Point ) );
272
273 if( pInitPoly )
274 memcpy( pNewAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
275 else
276 memset( pNewAry + nPos, 0, nSpaceSize );
277
278 memcpy( pNewAry + nSecPos, mpPointAry + nPos, nRest * sizeof( Point ) );
279 delete[] (char*) mpPointAry;
280
281 // ggf. FlagArray beruecksichtigen
282 if( mpFlagAry )
283 {
284 sal_uInt8* pNewFlagAry = new sal_uInt8[ nNewSize ];
285
286 memcpy( pNewFlagAry, mpFlagAry, nPos );
287
288 if( pInitPoly && pInitPoly->mpFlagAry )
289 memcpy( pNewFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
290 else
291 memset( pNewFlagAry + nPos, 0, nSpace );
292
293 memcpy( pNewFlagAry + nSecPos, mpFlagAry + nPos, nRest );
294 delete[] mpFlagAry;
295 mpFlagAry = pNewFlagAry;
296 }
297
298 mpPointAry = pNewAry;
299 mnPoints = nNewSize;
300 }
301 }
302
303 // -----------------------------------------------------------------------
304
ImplRemove(sal_uInt16 nPos,sal_uInt16 nCount)305 void ImplPolygon::ImplRemove( sal_uInt16 nPos, sal_uInt16 nCount )
306 {
307 const sal_uInt16 nRemoveCount = Min( (sal_uInt16) ( mnPoints - nPos ), (sal_uInt16) nCount );
308
309 if( nRemoveCount )
310 {
311 const sal_uInt16 nNewSize = mnPoints - nRemoveCount;
312 const sal_uInt16 nSecPos = nPos + nRemoveCount;
313 const sal_uInt16 nRest = mnPoints - nSecPos;
314
315 Point* pNewAry = (Point*) new char[ (sal_uIntPtr) nNewSize * sizeof( Point ) ];
316
317 memcpy( pNewAry, mpPointAry, nPos * sizeof( Point ) );
318 memcpy( pNewAry + nPos, mpPointAry + nSecPos, nRest * sizeof( Point ) );
319
320 delete[] (char*) mpPointAry;
321
322 // ggf. FlagArray beruecksichtigen
323 if( mpFlagAry )
324 {
325 sal_uInt8* pNewFlagAry = new sal_uInt8[ nNewSize ];
326
327 memcpy( pNewFlagAry, mpFlagAry, nPos );
328 memcpy( pNewFlagAry + nPos, mpFlagAry + nSecPos, nRest );
329 delete[] mpFlagAry;
330 mpFlagAry = pNewFlagAry;
331 }
332
333 mpPointAry = pNewAry;
334 mnPoints = nNewSize;
335 }
336 }
337
338 // -----------------------------------------------------------------------
339
ImplCreateFlagArray()340 void ImplPolygon::ImplCreateFlagArray()
341 {
342 if( !mpFlagAry )
343 {
344 mpFlagAry = new sal_uInt8[ mnPoints ];
345 memset( mpFlagAry, 0, mnPoints );
346 }
347 }
348
349 // =======================================================================
350
ImplMakeUnique()351 inline void Polygon::ImplMakeUnique()
352 {
353 // Falls noch andere Referenzen bestehen, dann kopieren
354 if ( mpImplPolygon->mnRefCount != 1 )
355 {
356 if ( mpImplPolygon->mnRefCount )
357 mpImplPolygon->mnRefCount--;
358 mpImplPolygon = new ImplPolygon( *mpImplPolygon );
359 }
360 }
361
362 // -----------------------------------------------------------------------
363
ImplGetAngle(const Point & rCenter,const Point & rPt)364 inline double ImplGetAngle( const Point& rCenter, const Point& rPt )
365 {
366 const long nDX = rPt.X() - rCenter.X();
367 return( atan2( -rPt.Y() + rCenter.Y(), ( ( nDX == 0L ) ? 0.000000001 : nDX ) ) );
368 }
369
370 // -----------------------------------------------------------------------
371
Polygon()372 Polygon::Polygon()
373 {
374 DBG_CTOR( Polygon, NULL );
375 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
376 }
377
378 // -----------------------------------------------------------------------
379
Polygon(sal_uInt16 nSize)380 Polygon::Polygon( sal_uInt16 nSize )
381 {
382 DBG_CTOR( Polygon, NULL );
383
384 if ( nSize )
385 mpImplPolygon = new ImplPolygon( nSize );
386 else
387 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
388 }
389
390 // -----------------------------------------------------------------------
391
Polygon(sal_uInt16 nPoints,const Point * pPtAry,const sal_uInt8 * pFlagAry)392 Polygon::Polygon( sal_uInt16 nPoints, const Point* pPtAry, const sal_uInt8* pFlagAry )
393 {
394 DBG_CTOR( Polygon, NULL );
395
396 if( nPoints )
397 mpImplPolygon = new ImplPolygon( nPoints, pPtAry, pFlagAry );
398 else
399 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
400 }
401
402 // -----------------------------------------------------------------------
403
Polygon(const Polygon & rPoly)404 Polygon::Polygon( const Polygon& rPoly )
405 {
406 DBG_CTOR( Polygon, NULL );
407 DBG_CHKOBJ( &rPoly, Polygon, NULL );
408 DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
409
410 mpImplPolygon = rPoly.mpImplPolygon;
411 if ( mpImplPolygon->mnRefCount )
412 mpImplPolygon->mnRefCount++;
413 }
414
415 // -----------------------------------------------------------------------
416
Polygon(const Rectangle & rRect)417 Polygon::Polygon( const Rectangle& rRect )
418 {
419 DBG_CTOR( Polygon, NULL );
420
421 if ( rRect.IsEmpty() )
422 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
423 else
424 {
425 mpImplPolygon = new ImplPolygon( 5 );
426 mpImplPolygon->mpPointAry[0] = rRect.TopLeft();
427 mpImplPolygon->mpPointAry[1] = rRect.TopRight();
428 mpImplPolygon->mpPointAry[2] = rRect.BottomRight();
429 mpImplPolygon->mpPointAry[3] = rRect.BottomLeft();
430 mpImplPolygon->mpPointAry[4] = rRect.TopLeft();
431 }
432 }
433
434 // -----------------------------------------------------------------------
435
Polygon(const Rectangle & rRect,sal_uIntPtr nHorzRound,sal_uIntPtr nVertRound)436 Polygon::Polygon( const Rectangle& rRect, sal_uIntPtr nHorzRound, sal_uIntPtr nVertRound )
437 {
438 DBG_CTOR( Polygon, NULL );
439
440 if ( rRect.IsEmpty() )
441 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
442 else
443 {
444 Rectangle aRect( rRect );
445 aRect.Justify(); // SJ: i9140
446
447 nHorzRound = Min( nHorzRound, (sal_uIntPtr) labs( aRect.GetWidth() >> 1 ) );
448 nVertRound = Min( nVertRound, (sal_uIntPtr) labs( aRect.GetHeight() >> 1 ) );
449
450 if( !nHorzRound && !nVertRound )
451 {
452 mpImplPolygon = new ImplPolygon( 5 );
453 mpImplPolygon->mpPointAry[0] = aRect.TopLeft();
454 mpImplPolygon->mpPointAry[1] = aRect.TopRight();
455 mpImplPolygon->mpPointAry[2] = aRect.BottomRight();
456 mpImplPolygon->mpPointAry[3] = aRect.BottomLeft();
457 mpImplPolygon->mpPointAry[4] = aRect.TopLeft();
458 }
459 else
460 {
461 const Point aTL( aRect.Left() + nHorzRound, aRect.Top() + nVertRound );
462 const Point aTR( aRect.Right() - nHorzRound, aRect.Top() + nVertRound );
463 const Point aBR( aRect.Right() - nHorzRound, aRect.Bottom() - nVertRound );
464 const Point aBL( aRect.Left() + nHorzRound, aRect.Bottom() - nVertRound );
465 Polygon* pEllipsePoly = new Polygon( Point(), nHorzRound, nVertRound );
466 sal_uInt16 i, nEnd, nSize4 = pEllipsePoly->GetSize() >> 2;
467
468 mpImplPolygon = new ImplPolygon( pEllipsePoly->GetSize() + 1 );
469
470 const Point* pSrcAry = pEllipsePoly->GetConstPointAry();
471 Point* pDstAry = mpImplPolygon->mpPointAry;
472
473 for( i = 0, nEnd = nSize4; i < nEnd; i++ )
474 ( pDstAry[ i ] = pSrcAry[ i ] ) += aTR;
475
476 for( nEnd = nEnd + nSize4; i < nEnd; i++ )
477 ( pDstAry[ i ] = pSrcAry[ i ] ) += aTL;
478
479 for( nEnd = nEnd + nSize4; i < nEnd; i++ )
480 ( pDstAry[ i ] = pSrcAry[ i ] ) += aBL;
481
482 for( nEnd = nEnd + nSize4; i < nEnd; i++ )
483 ( pDstAry[ i ] = pSrcAry[ i ] ) += aBR;
484
485 pDstAry[ nEnd ] = pDstAry[ 0 ];
486 delete pEllipsePoly;
487 }
488 }
489 }
490
491 // -----------------------------------------------------------------------
492
Polygon(const Point & rCenter,long nRadX,long nRadY,sal_uInt16 nPoints)493 Polygon::Polygon( const Point& rCenter, long nRadX, long nRadY, sal_uInt16 nPoints )
494 {
495 DBG_CTOR( Polygon, NULL );
496
497 if( nRadX && nRadY )
498 {
499 // Default berechnen (abhaengig von Groesse)
500 if( !nPoints )
501 {
502 nPoints = (sal_uInt16) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
503 sqrt( (double) labs( nRadX * nRadY ) ) ) );
504
505 nPoints = (sal_uInt16) MinMax( nPoints, 32, 256 );
506
507 if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
508 nPoints >>= 1;
509 }
510
511 // Anzahl der Punkte auf durch 4 teilbare Zahl aufrunden
512 mpImplPolygon = new ImplPolygon( nPoints = (nPoints + 3) & ~3 );
513
514 Point* pPt;
515 sal_uInt16 i;
516 sal_uInt16 nPoints2 = nPoints >> 1;
517 sal_uInt16 nPoints4 = nPoints >> 2;
518 double nAngle;
519 double nAngleStep = F_PI2 / ( nPoints4 - 1 );
520
521 for( i=0, nAngle = 0.0; i < nPoints4; i++, nAngle += nAngleStep )
522 {
523 long nX = FRound( nRadX * cos( nAngle ) );
524 long nY = FRound( -nRadY * sin( nAngle ) );
525
526 pPt = &(mpImplPolygon->mpPointAry[i]);
527 pPt->X() = nX + rCenter.X();
528 pPt->Y() = nY + rCenter.Y();
529 pPt = &(mpImplPolygon->mpPointAry[nPoints2-i-1]);
530 pPt->X() = -nX + rCenter.X();
531 pPt->Y() = nY + rCenter.Y();
532 pPt = &(mpImplPolygon->mpPointAry[i+nPoints2]);
533 pPt->X() = -nX + rCenter.X();
534 pPt->Y() = -nY + rCenter.Y();
535 pPt = &(mpImplPolygon->mpPointAry[nPoints-i-1]);
536 pPt->X() = nX + rCenter.X();
537 pPt->Y() = -nY + rCenter.Y();
538 }
539 }
540 else
541 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
542 }
543
544 // -----------------------------------------------------------------------
545
Polygon(const Rectangle & rBound,const Point & rStart,const Point & rEnd,PolyStyle eStyle)546 Polygon::Polygon( const Rectangle& rBound,
547 const Point& rStart, const Point& rEnd, PolyStyle eStyle )
548 {
549 DBG_CTOR( Polygon, NULL );
550
551 const long nWidth = rBound.GetWidth();
552 const long nHeight = rBound.GetHeight();
553
554 if( ( nWidth > 1 ) && ( nHeight > 1 ) )
555 {
556 const Point aCenter( rBound.Center() );
557 const long nRadX = aCenter.X() - rBound.Left();
558 const long nRadY = aCenter.Y() - rBound.Top();
559 sal_uInt16 nPoints;
560
561 nPoints = (sal_uInt16) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
562 sqrt( (double) labs( nRadX * nRadY ) ) ) );
563
564 nPoints = (sal_uInt16) MinMax( nPoints, 32, 256 );
565
566 if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
567 nPoints >>= 1;
568
569 // Winkel berechnen
570 const double fRadX = nRadX;
571 const double fRadY = nRadY;
572 const double fCenterX = aCenter.X();
573 const double fCenterY = aCenter.Y();
574 double fStart = ImplGetAngle( aCenter, rStart );
575 double fEnd = ImplGetAngle( aCenter, rEnd );
576 double fDiff = fEnd - fStart;
577 double fStep;
578 sal_uInt16 nStart;
579 sal_uInt16 nEnd;
580
581 if( fDiff < 0. )
582 fDiff += F_2PI;
583
584 // Punktanzahl proportional verkleinern ( fDiff / (2PI) );
585 // ist eingentlich nur fuer einen Kreis richtig; wir
586 // machen es hier aber trotzdem
587 nPoints = Max( (sal_uInt16) ( ( fDiff * 0.1591549 ) * nPoints ), (sal_uInt16) 16 );
588 fStep = fDiff / ( nPoints - 1 );
589
590 if( POLY_PIE == eStyle )
591 {
592 const Point aCenter2( FRound( fCenterX ), FRound( fCenterY ) );
593
594 nStart = 1;
595 nEnd = nPoints + 1;
596 mpImplPolygon = new ImplPolygon( nPoints + 2 );
597 mpImplPolygon->mpPointAry[ 0 ] = aCenter2;
598 mpImplPolygon->mpPointAry[ nEnd ] = aCenter2;
599 }
600 else
601 {
602 mpImplPolygon = new ImplPolygon( ( POLY_CHORD == eStyle ) ? ( nPoints + 1 ) : nPoints );
603 nStart = 0;
604 nEnd = nPoints;
605 }
606
607 for(; nStart < nEnd; nStart++, fStart += fStep )
608 {
609 Point& rPt = mpImplPolygon->mpPointAry[ nStart ];
610
611 rPt.X() = FRound( fCenterX + fRadX * cos( fStart ) );
612 rPt.Y() = FRound( fCenterY - fRadY * sin( fStart ) );
613 }
614
615 if( POLY_CHORD == eStyle )
616 mpImplPolygon->mpPointAry[ nPoints ] = mpImplPolygon->mpPointAry[ 0 ];
617 }
618 else
619 mpImplPolygon = (ImplPolygon*) &aStaticImplPolygon;
620 }
621
622 // -----------------------------------------------------------------------
623
Polygon(const Point & rBezPt1,const Point & rCtrlPt1,const Point & rBezPt2,const Point & rCtrlPt2,sal_uInt16 nPoints)624 Polygon::Polygon( const Point& rBezPt1, const Point& rCtrlPt1,
625 const Point& rBezPt2, const Point& rCtrlPt2,
626 sal_uInt16 nPoints )
627 {
628 DBG_CTOR( Polygon, NULL );
629
630 nPoints = ( 0 == nPoints ) ? 25 : ( ( nPoints < 2 ) ? 2 : nPoints );
631
632 const double fInc = 1.0 / ( nPoints - 1 );
633 double fK_1 = 0.0, fK1_1 = 1.0;
634 double fK_2, fK_3, fK1_2, fK1_3, fK12, fK21;
635 const double fX0 = rBezPt1.X();
636 const double fY0 = rBezPt1.Y();
637 const double fX1 = 3.0 * rCtrlPt1.X();
638 const double fY1 = 3.0 * rCtrlPt1.Y();
639 const double fX2 = 3.0 * rCtrlPt2.X();;
640 const double fY2 = 3.0 * rCtrlPt2.Y();;
641 const double fX3 = rBezPt2.X();
642 const double fY3 = rBezPt2.Y();
643
644 mpImplPolygon = new ImplPolygon( nPoints );
645
646 for( sal_uInt16 i = 0; i < nPoints; i++, fK_1 += fInc, fK1_1 -= fInc )
647 {
648 Point& rPt = mpImplPolygon->mpPointAry[ i ];
649
650 fK_2 = fK_1, fK_3 = ( fK_2 *= fK_1 ), fK_3 *= fK_1;
651 fK1_2 = fK1_1, fK1_3 = ( fK1_2 *= fK1_1 ), fK1_3 *= fK1_1;
652 fK12 = fK_1 * fK1_2, fK21 = fK_2 * fK1_1;
653
654 rPt.X() = FRound( fK1_3 * fX0 + fK12 * fX1 + fK21 * fX2 + fK_3 * fX3 );
655 rPt.Y() = FRound( fK1_3 * fY0 + fK12 * fY1 + fK21 * fY2 + fK_3 * fY3 );
656 }
657 }
658
659 // -----------------------------------------------------------------------
660
~Polygon()661 Polygon::~Polygon()
662 {
663 DBG_DTOR( Polygon, NULL );
664
665 // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
666 // die letzte Referenz ist, sonst Referenzcounter decrementieren
667 if ( mpImplPolygon->mnRefCount )
668 {
669 if ( mpImplPolygon->mnRefCount > 1 )
670 mpImplPolygon->mnRefCount--;
671 else
672 delete mpImplPolygon;
673 }
674 }
675
676 // -----------------------------------------------------------------------
677
ImplGetPointAry()678 Point* Polygon::ImplGetPointAry()
679 {
680 DBG_CHKTHIS( Polygon, NULL );
681
682 ImplMakeUnique();
683 return (Point*)mpImplPolygon->mpPointAry;
684 }
685
686 // -----------------------------------------------------------------------
687
ImplGetFlagAry()688 sal_uInt8* Polygon::ImplGetFlagAry()
689 {
690 DBG_CHKTHIS( Polygon, NULL );
691
692 ImplMakeUnique();
693 mpImplPolygon->ImplCreateFlagArray();
694 return mpImplPolygon->mpFlagAry;
695 }
696
697 // -----------------------------------------------------------------------
698
GetConstPointAry() const699 const Point* Polygon::GetConstPointAry() const
700 {
701 DBG_CHKTHIS( Polygon, NULL );
702 return (Point*)mpImplPolygon->mpPointAry;
703 }
704
705 // -----------------------------------------------------------------------
706
GetConstFlagAry() const707 const sal_uInt8* Polygon::GetConstFlagAry() const
708 {
709 DBG_CHKTHIS( Polygon, NULL );
710 return mpImplPolygon->mpFlagAry;
711 }
712
713 // -----------------------------------------------------------------------
714
SetPoint(const Point & rPt,sal_uInt16 nPos)715 void Polygon::SetPoint( const Point& rPt, sal_uInt16 nPos )
716 {
717 DBG_CHKTHIS( Polygon, NULL );
718 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
719 "Polygon::SetPoint(): nPos >= nPoints" );
720
721 ImplMakeUnique();
722 mpImplPolygon->mpPointAry[nPos] = rPt;
723 }
724
725 // -----------------------------------------------------------------------
726
SetFlags(sal_uInt16 nPos,PolyFlags eFlags)727 void Polygon::SetFlags( sal_uInt16 nPos, PolyFlags eFlags )
728 {
729 DBG_CHKTHIS( Polygon, NULL );
730 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
731 "Polygon::SetFlags(): nPos >= nPoints" );
732
733 // we do only want to create the flag array if there
734 // is at least one flag different to POLY_NORMAL
735 if ( mpImplPolygon || ( eFlags != POLY_NORMAL ) )
736 {
737 ImplMakeUnique();
738 mpImplPolygon->ImplCreateFlagArray();
739 mpImplPolygon->mpFlagAry[ nPos ] = (sal_uInt8) eFlags;
740 }
741 }
742
743 // -----------------------------------------------------------------------
744
GetPoint(sal_uInt16 nPos) const745 const Point& Polygon::GetPoint( sal_uInt16 nPos ) const
746 {
747 DBG_CHKTHIS( Polygon, NULL );
748 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
749 "Polygon::GetPoint(): nPos >= nPoints" );
750
751 return mpImplPolygon->mpPointAry[nPos];
752 }
753
754 // -----------------------------------------------------------------------
755
GetFlags(sal_uInt16 nPos) const756 PolyFlags Polygon::GetFlags( sal_uInt16 nPos ) const
757 {
758 DBG_CHKTHIS( Polygon, NULL );
759 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
760 "Polygon::GetFlags(): nPos >= nPoints" );
761 return( mpImplPolygon->mpFlagAry ?
762 (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] :
763 POLY_NORMAL );
764 }
765
766 // -----------------------------------------------------------------------
767
HasFlags() const768 sal_Bool Polygon::HasFlags() const
769 {
770 return mpImplPolygon->mpFlagAry != NULL;
771 }
772
773 // -----------------------------------------------------------------------
774
IsControl(sal_uInt16 nPos) const775 sal_Bool Polygon::IsControl(sal_uInt16 nPos) const
776 {
777 DBG_CHKTHIS( Polygon, NULL );
778 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
779 "Polygon::GetFlags(): nPos >= nPoints" );
780 PolyFlags eFlags = mpImplPolygon->mpFlagAry ?
781 (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] : POLY_NORMAL;
782
783 return( POLY_CONTROL == eFlags );
784 }
785
786 // -----------------------------------------------------------------------
787
IsSmooth(sal_uInt16 nPos) const788 sal_Bool Polygon::IsSmooth(sal_uInt16 nPos) const
789 {
790 DBG_CHKTHIS( Polygon, NULL );
791 DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
792 "Polygon::GetFlags(): nPos >= nPoints" );
793 PolyFlags eFlags = mpImplPolygon->mpFlagAry ?
794 (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] : POLY_NORMAL;
795
796 return( ( POLY_SMOOTH == eFlags ) || ( POLY_SYMMTR == eFlags ) );
797 }
798
799 // -----------------------------------------------------------------------
800
IsRect() const801 sal_Bool Polygon::IsRect() const
802 {
803 sal_Bool bIsRect = sal_False;
804 if ( mpImplPolygon->mpFlagAry == NULL )
805 {
806 if ( ( ( mpImplPolygon->mnPoints == 5 ) && ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ 4 ] ) ) ||
807 ( mpImplPolygon->mnPoints == 4 ) )
808 {
809 if ( ( mpImplPolygon->mpPointAry[ 0 ].X() == mpImplPolygon->mpPointAry[ 3 ].X() ) &&
810 ( mpImplPolygon->mpPointAry[ 0 ].Y() == mpImplPolygon->mpPointAry[ 1 ].Y() ) &&
811 ( mpImplPolygon->mpPointAry[ 1 ].X() == mpImplPolygon->mpPointAry[ 2 ].X() ) &&
812 ( mpImplPolygon->mpPointAry[ 2 ].Y() == mpImplPolygon->mpPointAry[ 3 ].Y() ) )
813 bIsRect = sal_True;
814 }
815 }
816 return bIsRect;
817 }
818
819 // -----------------------------------------------------------------------
820
SetSize(sal_uInt16 nNewSize)821 void Polygon::SetSize( sal_uInt16 nNewSize )
822 {
823 DBG_CHKTHIS( Polygon, NULL );
824
825 if( nNewSize != mpImplPolygon->mnPoints )
826 {
827 ImplMakeUnique();
828 mpImplPolygon->ImplSetSize( nNewSize );
829 }
830 }
831
832 // -----------------------------------------------------------------------
833
GetSize() const834 sal_uInt16 Polygon::GetSize() const
835 {
836 DBG_CHKTHIS( Polygon, NULL );
837
838 return mpImplPolygon->mnPoints;
839 }
840
841 // -----------------------------------------------------------------------
842
Clear()843 void Polygon::Clear()
844 {
845 DBG_CHKTHIS( Polygon, NULL );
846
847 if ( mpImplPolygon->mnRefCount )
848 {
849 if ( mpImplPolygon->mnRefCount > 1 )
850 mpImplPolygon->mnRefCount--;
851 else
852 delete mpImplPolygon;
853 }
854
855 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
856 }
857
858 // -----------------------------------------------------------------------
859
CalcDistance(sal_uInt16 nP1,sal_uInt16 nP2)860 double Polygon::CalcDistance( sal_uInt16 nP1, sal_uInt16 nP2 )
861 {
862 DBG_ASSERT( nP1 < mpImplPolygon->mnPoints,
863 "Polygon::CalcDistance(): nPos1 >= nPoints" );
864 DBG_ASSERT( nP2 < mpImplPolygon->mnPoints,
865 "Polygon::CalcDistance(): nPos2 >= nPoints" );
866
867 const Point& rP1 = mpImplPolygon->mpPointAry[ nP1 ];
868 const Point& rP2 = mpImplPolygon->mpPointAry[ nP2 ];
869 const double fDx = rP2.X() - rP1.X();
870 const double fDy = rP2.Y() - rP1.Y();
871
872 return sqrt( fDx * fDx + fDy * fDy );
873 }
874
875 // -----------------------------------------------------------------------
876
Optimize(sal_uIntPtr nOptimizeFlags,const PolyOptimizeData * pData)877 void Polygon::Optimize( sal_uIntPtr nOptimizeFlags, const PolyOptimizeData* pData )
878 {
879 DBG_CHKTHIS( Polygon, NULL );
880 DBG_ASSERT( !mpImplPolygon->mpFlagAry, "Optimizing could fail with beziers!" );
881
882 sal_uInt16 nSize = mpImplPolygon->mnPoints;
883
884 if( nOptimizeFlags && nSize )
885 {
886 if( nOptimizeFlags & POLY_OPTIMIZE_EDGES )
887 {
888 const Rectangle aBound( GetBoundRect() );
889 const double fArea = ( aBound.GetWidth() + aBound.GetHeight() ) * 0.5;
890 const sal_uInt16 nPercent = pData ? pData->GetPercentValue() : 50;
891
892 Optimize( POLY_OPTIMIZE_NO_SAME );
893 ImplReduceEdges( *this, fArea, nPercent );
894 }
895 else if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE | POLY_OPTIMIZE_NO_SAME ) )
896 {
897 Polygon aNewPoly;
898 const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
899 sal_uIntPtr nReduce;
900
901 if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE ) )
902 nReduce = pData ? pData->GetAbsValue() : 4UL;
903 else
904 nReduce = 0UL;
905
906 while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
907 nSize--;
908
909 if( nSize > 1 )
910 {
911 sal_uInt16 nLast = 0, nNewCount = 1;
912
913 aNewPoly.SetSize( nSize );
914 aNewPoly[ 0 ] = rFirst;
915
916 for( sal_uInt16 i = 1; i < nSize; i++ )
917 {
918 if( ( mpImplPolygon->mpPointAry[ i ] != mpImplPolygon->mpPointAry[ nLast ] ) &&
919 ( !nReduce || ( nReduce < (sal_uIntPtr) FRound( CalcDistance( nLast, i ) ) ) ) )
920 {
921 aNewPoly[ nNewCount++ ] = mpImplPolygon->mpPointAry[ nLast = i ];
922 }
923 }
924
925 if( nNewCount == 1 )
926 aNewPoly.Clear();
927 else
928 aNewPoly.SetSize( nNewCount );
929 }
930
931 *this = aNewPoly;
932 }
933
934 nSize = mpImplPolygon->mnPoints;
935
936 if( nSize > 1 )
937 {
938 if( ( nOptimizeFlags & POLY_OPTIMIZE_CLOSE ) &&
939 ( mpImplPolygon->mpPointAry[ 0 ] != mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
940 {
941 SetSize( mpImplPolygon->mnPoints + 1 );
942 mpImplPolygon->mpPointAry[ mpImplPolygon->mnPoints - 1 ] = mpImplPolygon->mpPointAry[ 0 ];
943 }
944 else if( ( nOptimizeFlags & POLY_OPTIMIZE_OPEN ) &&
945 ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
946 {
947 const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
948
949 while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
950 nSize--;
951
952 SetSize( nSize );
953 }
954 }
955 }
956 }
957
958 // =======================================================================
959
960 /* Recursively subdivide cubic bezier curve via deCasteljau.
961
962 @param rPointIter
963 Output iterator, where the subdivided polylines are written to.
964
965 @param d
966 Squared difference of curve to a straight line
967
968 @param P*
969 Exactly four points, interpreted as support and control points of
970 a cubic bezier curve. Must be in device coordinates, since stop
971 criterion is based on the following assumption: the device has a
972 finite resolution, it is thus sufficient to stop subdivision if the
973 curve does not deviate more than one pixel from a straight line.
974
975 */
ImplAdaptiveSubdivide(::std::back_insert_iterator<::std::vector<Point>> & rPointIter,const double old_d2,int recursionDepth,const double d2,const double P1x,const double P1y,const double P2x,const double P2y,const double P3x,const double P3y,const double P4x,const double P4y)976 static void ImplAdaptiveSubdivide( ::std::back_insert_iterator< ::std::vector< Point > >& rPointIter,
977 const double old_d2,
978 int recursionDepth,
979 const double d2,
980 const double P1x, const double P1y,
981 const double P2x, const double P2y,
982 const double P3x, const double P3y,
983 const double P4x, const double P4y )
984 {
985 // Hard limit on recursion depth, empiric number.
986 enum {maxRecursionDepth=128};
987
988 // Perform bezier flatness test (lecture notes from R. Schaback,
989 // Mathematics of Computer-Aided Design, Uni Goettingen, 2000)
990 //
991 // ||P(t) - L(t)|| <= max ||b_j - b_0 - j/n(b_n - b_0)||
992 // 0<=j<=n
993 //
994 // What is calculated here is an upper bound to the distance from
995 // a line through b_0 and b_3 (P1 and P4 in our notation) and the
996 // curve. We can drop 0 and n from the running indices, since the
997 // argument of max becomes zero for those cases.
998 const double fJ1x( P2x - P1x - 1.0/3.0*(P4x - P1x) );
999 const double fJ1y( P2y - P1y - 1.0/3.0*(P4y - P1y) );
1000 const double fJ2x( P3x - P1x - 2.0/3.0*(P4x - P1x) );
1001 const double fJ2y( P3y - P1y - 2.0/3.0*(P4y - P1y) );
1002 const double distance2( ::std::max( fJ1x*fJ1x + fJ1y*fJ1y,
1003 fJ2x*fJ2x + fJ2y*fJ2y) );
1004
1005 // stop if error measure does not improve anymore. This is a
1006 // safety guard against floating point inaccuracies.
1007 // stop at recursion level 128. This is a safety guard against
1008 // floating point inaccuracies.
1009 // stop if distance from line is guaranteed to be bounded by d
1010 if( old_d2 > d2 &&
1011 recursionDepth < maxRecursionDepth &&
1012 distance2 >= d2 )
1013 {
1014 // deCasteljau bezier arc, split at t=0.5
1015 // Foley/vanDam, p. 508
1016 const double L1x( P1x ), L1y( P1y );
1017 const double L2x( (P1x + P2x)*0.5 ), L2y( (P1y + P2y)*0.5 );
1018 const double Hx ( (P2x + P3x)*0.5 ), Hy ( (P2y + P3y)*0.5 );
1019 const double L3x( (L2x + Hx)*0.5 ), L3y( (L2y + Hy)*0.5 );
1020 const double R4x( P4x ), R4y( P4y );
1021 const double R3x( (P3x + P4x)*0.5 ), R3y( (P3y + P4y)*0.5 );
1022 const double R2x( (Hx + R3x)*0.5 ), R2y( (Hy + R3y)*0.5 );
1023 const double R1x( (L3x + R2x)*0.5 ), R1y( (L3y + R2y)*0.5 );
1024 const double L4x( R1x ), L4y( R1y );
1025
1026 // subdivide further
1027 ++recursionDepth;
1028 ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, L1x, L1y, L2x, L2y, L3x, L3y, L4x, L4y);
1029 ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, R1x, R1y, R2x, R2y, R3x, R3y, R4x, R4y);
1030 }
1031 else
1032 {
1033 // requested resolution reached.
1034 // Add end points to output iterator.
1035 // order is preserved, since this is so to say depth first traversal.
1036 *rPointIter++ = Point( FRound(P1x), FRound(P1y) );
1037 }
1038 }
1039
1040 // =======================================================================
1041
AdaptiveSubdivide(Polygon & rResult,const double d) const1042 void Polygon::AdaptiveSubdivide( Polygon& rResult, const double d ) const
1043 {
1044 if( !mpImplPolygon->mpFlagAry )
1045 {
1046 rResult = *this;
1047 }
1048 else
1049 {
1050 sal_uInt16 i;
1051 sal_uInt16 nPts( GetSize() );
1052 ::std::vector< Point > aPoints;
1053 aPoints.reserve( nPts );
1054 ::std::back_insert_iterator< ::std::vector< Point > > aPointIter( aPoints );
1055
1056 for(i=0; i<nPts;)
1057 {
1058 if( ( i + 3 ) < nPts )
1059 {
1060 sal_uInt8 P1( mpImplPolygon->mpFlagAry[ i ] );
1061 sal_uInt8 P4( mpImplPolygon->mpFlagAry[ i + 3 ] );
1062
1063 if( ( POLY_NORMAL == P1 || POLY_SMOOTH == P1 || POLY_SYMMTR == P1 ) &&
1064 ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 1 ] ) &&
1065 ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 2 ] ) &&
1066 ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
1067 {
1068 ImplAdaptiveSubdivide( aPointIter, d*d+1.0, 0, d*d,
1069 mpImplPolygon->mpPointAry[ i ].X(), mpImplPolygon->mpPointAry[ i ].Y(),
1070 mpImplPolygon->mpPointAry[ i+1 ].X(), mpImplPolygon->mpPointAry[ i+1 ].Y(),
1071 mpImplPolygon->mpPointAry[ i+2 ].X(), mpImplPolygon->mpPointAry[ i+2 ].Y(),
1072 mpImplPolygon->mpPointAry[ i+3 ].X(), mpImplPolygon->mpPointAry[ i+3 ].Y() );
1073 i += 3;
1074 continue;
1075 }
1076 }
1077
1078 *aPointIter++ = mpImplPolygon->mpPointAry[ i++ ];
1079
1080 if (aPoints.size() >= SAL_MAX_UINT16)
1081 {
1082 OSL_ENSURE(aPoints.size() < SAL_MAX_UINT16,
1083 "Polygon::AdapativeSubdivision created polygon too many points;"
1084 " using original polygon instead");
1085
1086 // The resulting polygon can not hold all the points
1087 // that we have created so far. Stop the subdivision
1088 // and return a copy of the unmodified polygon.
1089 rResult = *this;
1090 return;
1091 }
1092 }
1093
1094 // fill result polygon
1095 rResult = Polygon( (sal_uInt16)aPoints.size() ); // ensure sufficient size for copy
1096 ::std::copy(aPoints.begin(), aPoints.end(), rResult.mpImplPolygon->mpPointAry);
1097 }
1098 }
1099
1100 // -----------------------------------------------------------------------
1101
GetIntersection(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1102 void Polygon::GetIntersection( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1103 {
1104 const PolyPolygon aTmp( *this );
1105 aTmp.GetIntersection( rPolyPoly, rResult );
1106 }
1107
1108 // -----------------------------------------------------------------------
1109
GetUnion(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1110 void Polygon::GetUnion( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1111 {
1112 const PolyPolygon aTmp( *this );
1113 aTmp.GetUnion( rPolyPoly, rResult );
1114 }
1115
1116 // -----------------------------------------------------------------------
1117
GetDifference(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1118 void Polygon::GetDifference( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1119 {
1120 const PolyPolygon aTmp( *this );
1121 aTmp.GetDifference( rPolyPoly, rResult );
1122 }
1123
1124 // -----------------------------------------------------------------------
1125
GetXOR(const PolyPolygon & rPolyPoly,PolyPolygon & rResult) const1126 void Polygon::GetXOR( const PolyPolygon& rPolyPoly, PolyPolygon& rResult ) const
1127 {
1128 const PolyPolygon aTmp( *this );
1129 aTmp.GetXOR( rPolyPoly, rResult );
1130 }
1131
1132 // -----------------------------------------------------------------------
1133
ImplReduceEdges(Polygon & rPoly,const double & rArea,sal_uInt16 nPercent)1134 void Polygon::ImplReduceEdges( Polygon& rPoly, const double& rArea, sal_uInt16 nPercent )
1135 {
1136 const double fBound = 2000.0 * ( 100 - nPercent ) * 0.01;
1137 sal_uInt16 nNumNoChange = 0, nNumRuns = 0;
1138
1139 while( nNumNoChange < 2 )
1140 {
1141 sal_uInt16 nPntCnt = rPoly.GetSize(), nNewPos = 0;
1142 Polygon aNewPoly( nPntCnt );
1143 sal_Bool bChangeInThisRun = sal_False;
1144
1145 for( sal_uInt16 n = 0; n < nPntCnt; n++ )
1146 {
1147 sal_Bool bDeletePoint = sal_False;
1148
1149 if( ( n + nNumRuns ) % 2 )
1150 {
1151 sal_uInt16 nIndPrev = !n ? nPntCnt - 1 : n - 1;
1152 sal_uInt16 nIndPrevPrev = !nIndPrev ? nPntCnt - 1 : nIndPrev - 1;
1153 sal_uInt16 nIndNext = ( n == nPntCnt-1 ) ? 0 : n + 1;
1154 sal_uInt16 nIndNextNext = ( nIndNext == nPntCnt - 1 ) ? 0 : nIndNext + 1;
1155 Vector2D aVec1( rPoly[ nIndPrev ] ); aVec1 -= rPoly[ nIndPrevPrev ];
1156 Vector2D aVec2( rPoly[ n ] ); aVec2 -= rPoly[ nIndPrev ];
1157 Vector2D aVec3( rPoly[ nIndNext ] ); aVec3 -= rPoly[ n ];
1158 Vector2D aVec4( rPoly[ nIndNextNext ] ); aVec4 -= rPoly[ nIndNext ];
1159 double fDist1 = aVec1.GetLength(), fDist2 = aVec2.GetLength();
1160 double fDist3 = aVec3.GetLength(), fDist4 = aVec4.GetLength();
1161 double fTurnB = aVec2.Normalize().Scalar( aVec3.Normalize() );
1162
1163 if( fabs( fTurnB ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnB ) > ( 1.0 - SMALL_DVALUE ) )
1164 bDeletePoint = sal_True;
1165 else
1166 {
1167 Vector2D aVecB( rPoly[ nIndNext ] );
1168 double fDistB = ( aVecB -= rPoly[ nIndPrev ] ).GetLength();
1169 double fLenWithB = fDist2 + fDist3;
1170 double fLenFact = ( fDistB != 0.0 ) ? fLenWithB / fDistB : 1.0;
1171 double fTurnPrev = aVec1.Normalize().Scalar( aVec2 );
1172 double fTurnNext = aVec3.Scalar( aVec4.Normalize() );
1173 double fGradPrev, fGradB, fGradNext;
1174
1175 if( fabs( fTurnPrev ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnPrev ) > ( 1.0 - SMALL_DVALUE ) )
1176 fGradPrev = 0.0;
1177 else
1178 fGradPrev = acos( fTurnPrev ) / ( aVec1.IsNegative( aVec2 ) ? -F_PI180 : F_PI180 );
1179
1180 fGradB = acos( fTurnB ) / ( aVec2.IsNegative( aVec3 ) ? -F_PI180 : F_PI180 );
1181
1182 if( fabs( fTurnNext ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnNext ) > ( 1.0 - SMALL_DVALUE ) )
1183 fGradNext = 0.0;
1184 else
1185 fGradNext = acos( fTurnNext ) / ( aVec3.IsNegative( aVec4 ) ? -F_PI180 : F_PI180 );
1186
1187 if( ( fGradPrev > 0.0 && fGradB < 0.0 && fGradNext > 0.0 ) ||
1188 ( fGradPrev < 0.0 && fGradB > 0.0 && fGradNext < 0.0 ) )
1189 {
1190 if( ( fLenFact < ( FSQRT2 + SMALL_DVALUE ) ) &&
1191 ( ( ( fDist1 + fDist4 ) / ( fDist2 + fDist3 ) ) * 2000.0 ) > fBound )
1192 {
1193 bDeletePoint = sal_True;
1194 }
1195 }
1196 else
1197 {
1198 double fRelLen = 1.0 - sqrt( fDistB / rArea );
1199
1200 if( fRelLen < 0.0 )
1201 fRelLen = 0.0;
1202 else if( fRelLen > 1.0 )
1203 fRelLen = 1.0;
1204
1205 if( ( (sal_uInt32) ( ( ( fLenFact - 1.0 ) * 1000000.0 ) + 0.5 ) < fBound ) &&
1206 ( fabs( fGradB ) <= ( fRelLen * fBound * 0.01 ) ) )
1207 {
1208 bDeletePoint = sal_True;
1209 }
1210 }
1211 }
1212 }
1213
1214 if( !bDeletePoint )
1215 aNewPoly[ nNewPos++ ] = rPoly[ n ];
1216 else
1217 bChangeInThisRun = sal_True;
1218 }
1219
1220 if( bChangeInThisRun && nNewPos )
1221 {
1222 aNewPoly.SetSize( nNewPos );
1223 rPoly = aNewPoly;
1224 nNumNoChange = 0;
1225 }
1226 else
1227 nNumNoChange++;
1228
1229 nNumRuns++;
1230 }
1231 }
1232
1233 // -----------------------------------------------------------------------
1234
Move(long nHorzMove,long nVertMove)1235 void Polygon::Move( long nHorzMove, long nVertMove )
1236 {
1237 DBG_CHKTHIS( Polygon, NULL );
1238
1239 // Diese Abfrage sollte man fuer die DrawEngine durchfuehren
1240 if ( !nHorzMove && !nVertMove )
1241 return;
1242
1243 ImplMakeUnique();
1244
1245 // Punkte verschieben
1246 sal_uInt16 nCount = mpImplPolygon->mnPoints;
1247 for ( sal_uInt16 i = 0; i < nCount; i++ )
1248 {
1249 Point* pPt = &(mpImplPolygon->mpPointAry[i]);
1250 pPt->X() += nHorzMove;
1251 pPt->Y() += nVertMove;
1252 }
1253 }
1254
1255 // -----------------------------------------------------------------------
1256
Translate(const Point & rTrans)1257 void Polygon::Translate(const Point& rTrans)
1258 {
1259 DBG_CHKTHIS( Polygon, NULL );
1260 ImplMakeUnique();
1261
1262 for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1263 mpImplPolygon->mpPointAry[ i ] += rTrans;
1264 }
1265
1266 // -----------------------------------------------------------------------
1267
Scale(double fScaleX,double fScaleY)1268 void Polygon::Scale( double fScaleX, double fScaleY )
1269 {
1270 DBG_CHKTHIS( Polygon, NULL );
1271 ImplMakeUnique();
1272
1273 for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1274 {
1275 Point& rPnt = mpImplPolygon->mpPointAry[i];
1276 rPnt.X() = (long) ( fScaleX * rPnt.X() );
1277 rPnt.Y() = (long) ( fScaleY * rPnt.Y() );
1278 }
1279 }
1280
1281 // -----------------------------------------------------------------------
1282
Rotate(const Point & rCenter,sal_uInt16 nAngle10)1283 void Polygon::Rotate( const Point& rCenter, sal_uInt16 nAngle10 )
1284 {
1285 DBG_CHKTHIS( Polygon, NULL );
1286 nAngle10 %= 3600;
1287
1288 if( nAngle10 )
1289 {
1290 const double fAngle = F_PI1800 * nAngle10;
1291 Rotate( rCenter, sin( fAngle ), cos( fAngle ) );
1292 }
1293 }
1294
1295 // -----------------------------------------------------------------------
1296
Rotate(const Point & rCenter,double fSin,double fCos)1297 void Polygon::Rotate( const Point& rCenter, double fSin, double fCos )
1298 {
1299 DBG_CHKTHIS( Polygon, NULL );
1300 ImplMakeUnique();
1301
1302 long nX, nY;
1303 long nCenterX = rCenter.X();
1304 long nCenterY = rCenter.Y();
1305
1306 for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1307 {
1308 Point& rPt = mpImplPolygon->mpPointAry[ i ];
1309
1310 nX = rPt.X() - nCenterX;
1311 nY = rPt.Y() - nCenterY;
1312 rPt.X() = (long) FRound( fCos * nX + fSin * nY ) + nCenterX;
1313 rPt.Y() = -(long) FRound( fSin * nX - fCos * nY ) + nCenterY;
1314 }
1315 }
1316
1317 // -----------------------------------------------------------------------
1318
SlantX(long nYRef,double fSin,double fCos)1319 void Polygon::SlantX( long nYRef, double fSin, double fCos )
1320 {
1321 DBG_CHKTHIS( Polygon, NULL );
1322 ImplMakeUnique();
1323
1324 for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1325 {
1326 Point& rPnt = mpImplPolygon->mpPointAry[ i ];
1327 const long nDy = rPnt.Y() - nYRef;
1328
1329 rPnt.X() += (long)( fSin * nDy );
1330 rPnt.Y() = nYRef + (long)( fCos * nDy );
1331 }
1332 }
1333
1334 // -----------------------------------------------------------------------
1335
SlantY(long nXRef,double fSin,double fCos)1336 void Polygon::SlantY( long nXRef, double fSin, double fCos )
1337 {
1338 DBG_CHKTHIS( Polygon, NULL );
1339 ImplMakeUnique();
1340
1341 for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1342 {
1343 Point& rPnt = mpImplPolygon->mpPointAry[ i ];
1344 const long nDx = rPnt.X() - nXRef;
1345
1346 rPnt.X() = nXRef + (long)( fCos * nDx );
1347 rPnt.Y() -= (long)( fSin * nDx );
1348 }
1349 }
1350
1351 // -----------------------------------------------------------------------
1352
Distort(const Rectangle & rRefRect,const Polygon & rDistortedRect)1353 void Polygon::Distort( const Rectangle& rRefRect, const Polygon& rDistortedRect )
1354 {
1355 DBG_CHKTHIS( Polygon, NULL );
1356 ImplMakeUnique();
1357
1358 long Xr, Wr, X1, X2, X3, X4;
1359 long Yr, Hr, Y1, Y2, Y3, Y4;
1360 double fTx, fTy, fUx, fUy;
1361
1362 Xr = rRefRect.Left();
1363 Yr = rRefRect.Top();
1364 Wr = rRefRect.GetWidth();
1365 Hr = rRefRect.GetHeight();
1366
1367 if( Wr && Hr )
1368 {
1369 DBG_ASSERT( rDistortedRect.mpImplPolygon->mnPoints >= 4, "Distort rect too small!" );
1370
1371 X1 = rDistortedRect[0].X();
1372 Y1 = rDistortedRect[0].Y();
1373 X2 = rDistortedRect[1].X();
1374 Y2 = rDistortedRect[1].Y();
1375 X3 = rDistortedRect[3].X();
1376 Y3 = rDistortedRect[3].Y();
1377 X4 = rDistortedRect[2].X();
1378 Y4 = rDistortedRect[2].Y();
1379
1380 for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1381 {
1382 Point& rPnt = mpImplPolygon->mpPointAry[ i ];
1383
1384 fTx = (double)( rPnt.X() - Xr) / Wr;
1385 fTy = (double)( rPnt.Y() - Yr) / Hr;
1386 fUx = 1.0 - fTx;
1387 fUy = 1.0 - fTy;
1388
1389 rPnt.X() = (long) ( fUy * (fUx * X1 + fTx * X2) + fTy * (fUx * X3 + fTx * X4) );
1390 rPnt.Y() = (long) ( fUx * (fUy * Y1 + fTy * Y3) + fTx * (fUy * Y2 + fTy * Y4) );
1391 }
1392 }
1393 }
1394
1395 // -----------------------------------------------------------------------
1396
1397 class ImplPointFilter
1398 {
1399 public:
1400 virtual void LastPoint() = 0;
1401 virtual void Input( const Point& rPoint ) = 0;
1402 };
1403
1404 class ImplPolygonPointFilter : public ImplPointFilter
1405 {
1406 public:
1407 ImplPolygon* mpPoly; // Nicht loeschen, wird dem Polygon zugewiesen
1408 sal_uInt16 mnSize;
1409
ImplPolygonPointFilter(sal_uInt16 nDestSize)1410 ImplPolygonPointFilter( sal_uInt16 nDestSize ) :
1411 mnSize( 0 )
1412 {
1413 mpPoly = new ImplPolygon( nDestSize );
1414 }
1415
1416 virtual void LastPoint();
1417 virtual void Input( const Point& rPoint );
1418 };
1419
Input(const Point & rPoint)1420 void ImplPolygonPointFilter::Input( const Point& rPoint )
1421 {
1422 if ( !mnSize || (rPoint != mpPoly->mpPointAry[mnSize-1]) )
1423 {
1424 mnSize++;
1425 if ( mnSize > mpPoly->mnPoints )
1426 mpPoly->ImplSetSize( mnSize );
1427 mpPoly->mpPointAry[mnSize-1] = rPoint;
1428 }
1429 }
1430
LastPoint()1431 void ImplPolygonPointFilter::LastPoint()
1432 {
1433 if ( mnSize < mpPoly->mnPoints )
1434 mpPoly->ImplSetSize( mnSize );
1435 };
1436
1437 class ImplEdgePointFilter : public ImplPointFilter
1438 {
1439 Point maFirstPoint;
1440 Point maLastPoint;
1441 ImplPointFilter& mrNextFilter;
1442 const long mnLow;
1443 const long mnHigh;
1444 const int mnEdge;
1445 int mnLastOutside;
1446 sal_Bool mbFirst;
1447
1448 public:
ImplEdgePointFilter(int nEdge,long nLow,long nHigh,ImplPointFilter & rNextFilter)1449 ImplEdgePointFilter( int nEdge, long nLow, long nHigh,
1450 ImplPointFilter& rNextFilter ) :
1451 mrNextFilter( rNextFilter ),
1452 mnLow( nLow ),
1453 mnHigh( nHigh ),
1454 mnEdge( nEdge ),
1455 mbFirst( sal_True )
1456 {
1457 }
1458
1459 Point EdgeSection( const Point& rPoint, int nEdge ) const;
1460 int VisibleSide( const Point& rPoint ) const;
IsPolygon() const1461 int IsPolygon() const
1462 { return maFirstPoint == maLastPoint; }
1463
1464 virtual void Input( const Point& rPoint );
1465 virtual void LastPoint();
1466 };
1467
VisibleSide(const Point & rPoint) const1468 inline int ImplEdgePointFilter::VisibleSide( const Point& rPoint ) const
1469 {
1470 if ( mnEdge & EDGE_HORZ )
1471 {
1472 return rPoint.X() < mnLow ? EDGE_LEFT :
1473 rPoint.X() > mnHigh ? EDGE_RIGHT : 0;
1474 }
1475 else
1476 {
1477 return rPoint.Y() < mnLow ? EDGE_TOP :
1478 rPoint.Y() > mnHigh ? EDGE_BOTTOM : 0;
1479 }
1480 }
1481
EdgeSection(const Point & rPoint,int nEdge) const1482 Point ImplEdgePointFilter::EdgeSection( const Point& rPoint, int nEdge ) const
1483 {
1484 long lx = maLastPoint.X();
1485 long ly = maLastPoint.Y();
1486 long md = rPoint.X() - lx;
1487 long mn = rPoint.Y() - ly;
1488 long nNewX;
1489 long nNewY;
1490
1491 if ( nEdge & EDGE_VERT )
1492 {
1493 nNewY = (nEdge == EDGE_TOP) ? mnLow : mnHigh;
1494 long dy = nNewY - ly;
1495 if ( !md )
1496 nNewX = lx;
1497 else if ( (LONG_MAX / Abs(md)) >= Abs(dy) )
1498 nNewX = (dy * md) / mn + lx;
1499 else
1500 {
1501 BigInt ady = dy;
1502 ady *= md;
1503 if( ady.IsNeg() )
1504 if( mn < 0 )
1505 ady += mn/2;
1506 else
1507 ady -= (mn-1)/2;
1508 else
1509 if( mn < 0 )
1510 ady -= (mn+1)/2;
1511 else
1512 ady += mn/2;
1513 ady /= mn;
1514 nNewX = (long)ady + lx;
1515 }
1516 }
1517 else
1518 {
1519 nNewX = (nEdge == EDGE_LEFT) ? mnLow : mnHigh;
1520 long dx = nNewX - lx;
1521 if ( !mn )
1522 nNewY = ly;
1523 else if ( (LONG_MAX / Abs(mn)) >= Abs(dx) )
1524 nNewY = (dx * mn) / md + ly;
1525 else
1526 {
1527 BigInt adx = dx;
1528 adx *= mn;
1529 if( adx.IsNeg() )
1530 if( md < 0 )
1531 adx += md/2;
1532 else
1533 adx -= (md-1)/2;
1534 else
1535 if( md < 0 )
1536 adx -= (md+1)/2;
1537 else
1538 adx += md/2;
1539 adx /= md;
1540 nNewY = (long)adx + ly;
1541 }
1542 }
1543
1544 return Point( nNewX, nNewY );
1545 }
1546
Input(const Point & rPoint)1547 void ImplEdgePointFilter::Input( const Point& rPoint )
1548 {
1549 int nOutside = VisibleSide( rPoint );
1550
1551 if ( mbFirst )
1552 {
1553 maFirstPoint = rPoint;
1554 mbFirst = sal_False;
1555 if ( !nOutside )
1556 mrNextFilter.Input( rPoint );
1557 }
1558 else if ( rPoint == maLastPoint )
1559 return;
1560 else if ( !nOutside )
1561 {
1562 if ( mnLastOutside )
1563 mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1564 mrNextFilter.Input( rPoint );
1565 }
1566 else if ( !mnLastOutside )
1567 mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1568 else if ( nOutside != mnLastOutside )
1569 {
1570 mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1571 mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1572 }
1573
1574 maLastPoint = rPoint;
1575 mnLastOutside = nOutside;
1576 }
1577
LastPoint()1578 void ImplEdgePointFilter::LastPoint()
1579 {
1580 if ( !mbFirst )
1581 {
1582 int nOutside = VisibleSide( maFirstPoint );
1583
1584 if ( nOutside != mnLastOutside )
1585 Input( maFirstPoint );
1586 mrNextFilter.LastPoint();
1587 }
1588 }
1589
1590 // -----------------------------------------------------------------------
1591
Clip(const Rectangle & rRect,sal_Bool bPolygon)1592 void Polygon::Clip( const Rectangle& rRect, sal_Bool bPolygon )
1593 {
1594 // #105251# Justify rect befor edge filtering
1595 Rectangle aJustifiedRect( rRect );
1596 aJustifiedRect.Justify();
1597
1598 sal_uInt16 nSourceSize = mpImplPolygon->mnPoints;
1599 ImplPolygonPointFilter aPolygon( nSourceSize );
1600 ImplEdgePointFilter aHorzFilter( EDGE_HORZ, aJustifiedRect.Left(), aJustifiedRect.Right(),
1601 aPolygon );
1602 ImplEdgePointFilter aVertFilter( EDGE_VERT, aJustifiedRect.Top(), aJustifiedRect.Bottom(),
1603 aHorzFilter );
1604
1605 for ( sal_uInt16 i = 0; i < nSourceSize; i++ )
1606 aVertFilter.Input( mpImplPolygon->mpPointAry[i] );
1607 if ( bPolygon || aVertFilter.IsPolygon() )
1608 aVertFilter.LastPoint();
1609 else
1610 aPolygon.LastPoint();
1611
1612 // Alte ImpPolygon-Daten loeschen und die vom ImpPolygonPointFilter
1613 // zuweisen
1614 if ( mpImplPolygon->mnRefCount )
1615 {
1616 if ( mpImplPolygon->mnRefCount > 1 )
1617 mpImplPolygon->mnRefCount--;
1618 else
1619 delete mpImplPolygon;
1620 }
1621 mpImplPolygon = aPolygon.mpPoly;
1622 }
1623
1624 // -----------------------------------------------------------------------
1625
GetBoundRect() const1626 Rectangle Polygon::GetBoundRect() const
1627 {
1628 DBG_CHKTHIS( Polygon, NULL );
1629 // Removing the assert. Bezier curves have the attribute that each single
1630 // curve segment defined by four points can not exit the four-point polygon
1631 // defined by that points. This allows to say that the curve segment can also
1632 // never leave the Range of it's defining points.
1633 // The result is that Polygon::GetBoundRect() may not create the minimal
1634 // BoundRect of the Polygon (to get that, use basegfx::B2DPolygon classes),
1635 // but will always create a valid BoundRect, at least as long as this method
1636 // 'blindly' travels over all points, including control points.
1637 //
1638 // DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetBoundRect could fail with beziers!" );
1639
1640 sal_uInt16 nCount = mpImplPolygon->mnPoints;
1641 if( ! nCount )
1642 return Rectangle();
1643
1644 long nXMin, nXMax, nYMin, nYMax;
1645
1646 const Point* pPt = &(mpImplPolygon->mpPointAry[0]);
1647 nXMin = nXMax = pPt->X();
1648 nYMin = nYMax = pPt->Y();
1649
1650 for ( sal_uInt16 i = 0; i < nCount; i++ )
1651 {
1652 pPt = &(mpImplPolygon->mpPointAry[i]);
1653
1654 if ( pPt->X() < nXMin )
1655 nXMin = pPt->X();
1656 if ( pPt->X() > nXMax )
1657 nXMax = pPt->X();
1658 if ( pPt->Y() < nYMin )
1659 nYMin = pPt->Y();
1660 if ( pPt->Y() > nYMax )
1661 nYMax = pPt->Y();
1662 }
1663
1664 return Rectangle( nXMin, nYMin, nXMax, nYMax );
1665 }
1666
1667 // -----------------------------------------------------------------------
1668
GetArea() const1669 double Polygon::GetArea() const
1670 {
1671 const double fArea = GetSignedArea();
1672 return( ( fArea < 0.0 ) ? -fArea : fArea );
1673 }
1674
1675 // -----------------------------------------------------------------------
1676
GetSignedArea() const1677 double Polygon::GetSignedArea() const
1678 {
1679 DBG_CHKTHIS( Polygon, NULL );
1680 DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetArea could fail with beziers!" );
1681
1682 double fArea = 0.0;
1683
1684 if( mpImplPolygon->mnPoints > 2 )
1685 {
1686 const sal_uInt16 nCount1 = mpImplPolygon->mnPoints - 1;
1687
1688 for( sal_uInt16 i = 0; i < nCount1; )
1689 {
1690 const Point& rPt = mpImplPolygon->mpPointAry[ i ];
1691 const Point& rPt1 = mpImplPolygon->mpPointAry[ ++i ];
1692 fArea += ( rPt.X() - rPt1.X() ) * ( rPt.Y() + rPt1.Y() );
1693 }
1694
1695 const Point& rPt = mpImplPolygon->mpPointAry[ nCount1 ];
1696 const Point& rPt0 = mpImplPolygon->mpPointAry[ 0 ];
1697 fArea += ( rPt.X() - rPt0.X() ) * ( rPt.Y() + rPt0.Y() );
1698 }
1699
1700 return fArea;
1701 }
1702
1703 // -----------------------------------------------------------------------
1704
IsInside(const Point & rPoint) const1705 sal_Bool Polygon::IsInside( const Point& rPoint ) const
1706 {
1707 DBG_CHKTHIS( Polygon, NULL );
1708 DBG_ASSERT( !mpImplPolygon->mpFlagAry, "IsInside could fail with beziers!" );
1709
1710 const Rectangle aBound( GetBoundRect() );
1711 const Line aLine( rPoint, Point( aBound.Right() + 100L, rPoint.Y() ) );
1712 sal_uInt16 nCount = mpImplPolygon->mnPoints;
1713 sal_uInt16 nPCounter = 0;
1714
1715 if ( ( nCount > 2 ) && aBound.IsInside( rPoint ) )
1716 {
1717 Point aPt1( mpImplPolygon->mpPointAry[ 0 ] );
1718 Point aIntersection;
1719 Point aLastIntersection;
1720
1721 while ( ( aPt1 == mpImplPolygon->mpPointAry[ nCount - 1 ] ) && ( nCount > 3 ) )
1722 nCount--;
1723
1724 for ( sal_uInt16 i = 1; i <= nCount; i++ )
1725 {
1726 const Point& rPt2 = mpImplPolygon->mpPointAry[ ( i < nCount ) ? i : 0 ];
1727
1728 if ( aLine.Intersection( Line( aPt1, rPt2 ), aIntersection ) )
1729 {
1730 // Hiermit verhindern wir das Einfuegen von
1731 // doppelten Intersections, die gleich hintereinander folgen
1732 if ( nPCounter )
1733 {
1734 if ( aIntersection != aLastIntersection )
1735 {
1736 aLastIntersection = aIntersection;
1737 nPCounter++;
1738 }
1739 }
1740 else
1741 {
1742 aLastIntersection = aIntersection;
1743 nPCounter++;
1744 }
1745 }
1746
1747 aPt1 = rPt2;
1748 }
1749 }
1750
1751 // innerhalb, wenn die Anzahl der Schnittpunkte ungerade ist
1752 return ( ( nPCounter & 1 ) == 1 );
1753 }
1754
1755 // -----------------------------------------------------------------------
1756
IsRightOrientated() const1757 sal_Bool Polygon::IsRightOrientated() const
1758 {
1759 DBG_CHKTHIS( Polygon, NULL );
1760 return GetSignedArea() >= 0.0;
1761 }
1762
1763 // -----------------------------------------------------------------------
1764
Insert(sal_uInt16 nPos,const Point & rPt,PolyFlags eFlags)1765 void Polygon::Insert( sal_uInt16 nPos, const Point& rPt, PolyFlags eFlags )
1766 {
1767 DBG_CHKTHIS( Polygon, NULL );
1768 ImplMakeUnique();
1769
1770 if( nPos >= mpImplPolygon->mnPoints )
1771 nPos = mpImplPolygon->mnPoints;
1772
1773 mpImplPolygon->ImplSplit( nPos, 1 );
1774 mpImplPolygon->mpPointAry[ nPos ] = rPt;
1775
1776 if( POLY_NORMAL != eFlags )
1777 {
1778 mpImplPolygon->ImplCreateFlagArray();
1779 mpImplPolygon->mpFlagAry[ nPos ] = (sal_uInt8) eFlags;
1780 }
1781 }
1782
1783 // -----------------------------------------------------------------------
1784
Insert(sal_uInt16 nPos,const Polygon & rPoly)1785 void Polygon::Insert( sal_uInt16 nPos, const Polygon& rPoly )
1786 {
1787 DBG_CHKTHIS( Polygon, NULL );
1788 const sal_uInt16 nInsertCount = rPoly.mpImplPolygon->mnPoints;
1789
1790 if( nInsertCount )
1791 {
1792 ImplMakeUnique();
1793
1794 if( nPos >= mpImplPolygon->mnPoints )
1795 nPos = mpImplPolygon->mnPoints;
1796
1797 if( rPoly.mpImplPolygon->mpFlagAry )
1798 mpImplPolygon->ImplCreateFlagArray();
1799
1800 mpImplPolygon->ImplSplit( nPos, nInsertCount, rPoly.mpImplPolygon );
1801 }
1802 }
1803
1804 // -----------------------------------------------------------------------
1805
Remove(sal_uInt16 nPos,sal_uInt16 nCount)1806 void Polygon::Remove( sal_uInt16 nPos, sal_uInt16 nCount )
1807 {
1808 DBG_CHKTHIS( Polygon, NULL );
1809 if( nCount && ( nPos < mpImplPolygon->mnPoints ) )
1810 {
1811 ImplMakeUnique();
1812 mpImplPolygon->ImplRemove( nPos, nCount );
1813 }
1814 }
1815
1816 // -----------------------------------------------------------------------
1817
operator [](sal_uInt16 nPos)1818 Point& Polygon::operator[]( sal_uInt16 nPos )
1819 {
1820 DBG_CHKTHIS( Polygon, NULL );
1821 DBG_ASSERT( nPos < mpImplPolygon->mnPoints, "Polygon::[]: nPos >= nPoints" );
1822
1823 ImplMakeUnique();
1824 return mpImplPolygon->mpPointAry[nPos];
1825 }
1826
1827 // -----------------------------------------------------------------------
1828
operator =(const Polygon & rPoly)1829 Polygon& Polygon::operator=( const Polygon& rPoly )
1830 {
1831 DBG_CHKTHIS( Polygon, NULL );
1832 DBG_CHKOBJ( &rPoly, Polygon, NULL );
1833 DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
1834
1835 // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
1836 // RefCount == 0 fuer statische Objekte
1837 if ( rPoly.mpImplPolygon->mnRefCount )
1838 rPoly.mpImplPolygon->mnRefCount++;
1839
1840 // Wenn es keine statischen ImpDaten sind, dann loeschen, wenn es
1841 // die letzte Referenz ist, sonst Referenzcounter decrementieren
1842 if ( mpImplPolygon->mnRefCount )
1843 {
1844 if ( mpImplPolygon->mnRefCount > 1 )
1845 mpImplPolygon->mnRefCount--;
1846 else
1847 delete mpImplPolygon;
1848 }
1849
1850 mpImplPolygon = rPoly.mpImplPolygon;
1851 return *this;
1852 }
1853
1854 // -----------------------------------------------------------------------
1855
operator ==(const Polygon & rPoly) const1856 sal_Bool Polygon::operator==( const Polygon& rPoly ) const
1857 {
1858 DBG_CHKTHIS( Polygon, NULL );
1859 DBG_CHKOBJ( &rPoly, Polygon, NULL );
1860
1861 if ( (rPoly.mpImplPolygon == mpImplPolygon) )
1862 return sal_True;
1863 else
1864 return sal_False;
1865 }
1866
1867 // -----------------------------------------------------------------------
1868
IsEqual(const Polygon & rPoly) const1869 sal_Bool Polygon::IsEqual( const Polygon& rPoly ) const
1870 {
1871 sal_Bool bIsEqual = sal_True;;
1872 sal_uInt16 i;
1873 if ( GetSize() != rPoly.GetSize() )
1874 bIsEqual = sal_False;
1875 else
1876 {
1877 for ( i = 0; i < GetSize(); i++ )
1878 {
1879 if ( ( GetPoint( i ) != rPoly.GetPoint( i ) ) ||
1880 ( GetFlags( i ) != rPoly.GetFlags( i ) ) )
1881 {
1882 bIsEqual = sal_False;
1883 break;
1884 }
1885 }
1886 }
1887 return bIsEqual;
1888 }
1889
1890 // -----------------------------------------------------------------------
1891
operator >>(SvStream & rIStream,Polygon & rPoly)1892 SvStream& operator>>( SvStream& rIStream, Polygon& rPoly )
1893 {
1894 DBG_CHKOBJ( &rPoly, Polygon, NULL );
1895 DBG_ASSERTWARNING( rIStream.GetVersion(), "Polygon::>> - Solar-Version not set on rIStream" );
1896
1897 sal_uInt16 i;
1898 sal_uInt16 nStart;
1899 sal_uInt16 nCurPoints;
1900 sal_uInt16 nPoints;
1901 unsigned char bShort;
1902 short nShortX;
1903 short nShortY;
1904 long nLongX;
1905 long nLongY;
1906
1907 // Anzahl der Punkte einlesen und Array erzeugen
1908 rIStream >> nPoints;
1909 if ( rPoly.mpImplPolygon->mnRefCount != 1 )
1910 {
1911 if ( rPoly.mpImplPolygon->mnRefCount )
1912 rPoly.mpImplPolygon->mnRefCount--;
1913 rPoly.mpImplPolygon = new ImplPolygon( nPoints );
1914 }
1915 else
1916 rPoly.mpImplPolygon->ImplSetSize( nPoints, sal_False );
1917
1918 // Je nach CompressMode das Polygon einlesen
1919 if ( rIStream.GetCompressMode() == COMPRESSMODE_FULL )
1920 {
1921 i = 0;
1922 while ( i < nPoints )
1923 {
1924 rIStream >> bShort >> nCurPoints;
1925
1926 if ( bShort )
1927 {
1928 for ( nStart = i; i < nStart+nCurPoints; i++ )
1929 {
1930 rIStream >> nShortX >> nShortY;
1931 rPoly.mpImplPolygon->mpPointAry[i].X() = nShortX;
1932 rPoly.mpImplPolygon->mpPointAry[i].Y() = nShortY;
1933 }
1934 }
1935 else
1936 {
1937 for ( nStart = i; i < nStart+nCurPoints; i++ )
1938 {
1939 rIStream >> nLongX >> nLongY;
1940 rPoly.mpImplPolygon->mpPointAry[i].X() = nLongX;
1941 rPoly.mpImplPolygon->mpPointAry[i].Y() = nLongY;
1942 }
1943 }
1944 }
1945 }
1946 else
1947 {
1948 // Feststellen, ob ueber die Operatoren geschrieben werden muss
1949 #if (SAL_TYPES_SIZEOFLONG) != 4
1950 if ( 1 )
1951 #else
1952 #ifdef OSL_BIGENDIAN
1953 if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
1954 #else
1955 if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
1956 #endif
1957 #endif
1958 {
1959 for( i = 0; i < nPoints; i++ )
1960 {
1961 rIStream >> rPoly.mpImplPolygon->mpPointAry[i].X()
1962 >> rPoly.mpImplPolygon->mpPointAry[i].Y();
1963 }
1964 }
1965 else
1966 rIStream.Read( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
1967 }
1968
1969 return rIStream;
1970 }
1971
1972 // -----------------------------------------------------------------------
1973
operator <<(SvStream & rOStream,const Polygon & rPoly)1974 SvStream& operator<<( SvStream& rOStream, const Polygon& rPoly )
1975 {
1976 DBG_CHKOBJ( &rPoly, Polygon, NULL );
1977 DBG_ASSERTWARNING( rOStream.GetVersion(), "Polygon::<< - Solar-Version not set on rOStream" );
1978
1979 unsigned char bShort;
1980 unsigned char bCurShort;
1981 sal_uInt16 nStart;
1982 sal_uInt16 i;
1983 sal_uInt16 nPoints = rPoly.GetSize();
1984
1985 // Anzahl der Punkte rausschreiben
1986 rOStream << nPoints;
1987
1988 // Je nach CompressMode das Polygon rausschreiben
1989 if ( rOStream.GetCompressMode() == COMPRESSMODE_FULL )
1990 {
1991 i = 0;
1992 while ( i < nPoints )
1993 {
1994 nStart = i;
1995
1996 // Feststellen, welcher Typ geschrieben werden soll
1997 if ( ((rPoly.mpImplPolygon->mpPointAry[nStart].X() >= SHRT_MIN) &&
1998 (rPoly.mpImplPolygon->mpPointAry[nStart].X() <= SHRT_MAX)) &&
1999 ((rPoly.mpImplPolygon->mpPointAry[nStart].Y() >= SHRT_MIN) &&
2000 (rPoly.mpImplPolygon->mpPointAry[nStart].Y() <= SHRT_MAX)) )
2001 bShort = sal_True;
2002 else
2003 bShort = sal_False;
2004 while ( i < nPoints )
2005 {
2006 // Feststellen, welcher Typ geschrieben werden soll
2007 if ( ((rPoly.mpImplPolygon->mpPointAry[nStart].X() >= SHRT_MIN) &&
2008 (rPoly.mpImplPolygon->mpPointAry[nStart].X() <= SHRT_MAX)) &&
2009 ((rPoly.mpImplPolygon->mpPointAry[nStart].Y() >= SHRT_MIN) &&
2010 (rPoly.mpImplPolygon->mpPointAry[nStart].Y() <= SHRT_MAX)) )
2011 bCurShort = sal_True;
2012 else
2013 bCurShort = sal_False;
2014
2015 // Wenn sich die Werte in einen anderen Bereich begeben,
2016 // muessen wir neu rausschreiben
2017 if ( bCurShort != bShort )
2018 {
2019 bShort = bCurShort;
2020 break;
2021 }
2022
2023 i++;
2024 }
2025
2026 rOStream << bShort << (sal_uInt16)(i-nStart);
2027
2028 if ( bShort )
2029 {
2030 for( ; nStart < i; nStart++ )
2031 {
2032 rOStream << (short)rPoly.mpImplPolygon->mpPointAry[nStart].X()
2033 << (short)rPoly.mpImplPolygon->mpPointAry[nStart].Y();
2034 }
2035 }
2036 else
2037 {
2038 for( ; nStart < i; nStart++ )
2039 {
2040 rOStream << rPoly.mpImplPolygon->mpPointAry[nStart].X()
2041 << rPoly.mpImplPolygon->mpPointAry[nStart].Y();
2042 }
2043 }
2044 }
2045 }
2046 else
2047 {
2048 // Feststellen, ob ueber die Operatoren geschrieben werden muss
2049 #if (SAL_TYPES_SIZEOFLONG) != 4
2050 if ( 1 )
2051 #else
2052 #ifdef OSL_BIGENDIAN
2053 if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
2054 #else
2055 if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
2056 #endif
2057 #endif
2058 {
2059 for( i = 0; i < nPoints; i++ )
2060 {
2061 rOStream << rPoly.mpImplPolygon->mpPointAry[i].X()
2062 << rPoly.mpImplPolygon->mpPointAry[i].Y();
2063 }
2064 }
2065 else
2066 {
2067 if ( nPoints )
2068 rOStream.Write( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
2069 }
2070 }
2071
2072 return rOStream;
2073 }
2074
2075 // -----------------------------------------------------------------------
2076
ImplRead(SvStream & rIStream)2077 void Polygon::ImplRead( SvStream& rIStream )
2078 {
2079 sal_uInt8 bHasPolyFlags;
2080
2081 rIStream >> *this
2082 >> bHasPolyFlags;
2083
2084 if ( bHasPolyFlags )
2085 {
2086 mpImplPolygon->mpFlagAry = new sal_uInt8[ mpImplPolygon->mnPoints ];
2087 rIStream.Read( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
2088 }
2089 }
2090
2091 // -----------------------------------------------------------------------
2092
Read(SvStream & rIStream)2093 void Polygon::Read( SvStream& rIStream )
2094 {
2095 VersionCompat aCompat( rIStream, STREAM_READ );
2096
2097 ImplRead( rIStream );
2098 }
2099
2100 // -----------------------------------------------------------------------
2101
ImplWrite(SvStream & rOStream) const2102 void Polygon::ImplWrite( SvStream& rOStream ) const
2103 {
2104 sal_uInt8 bHasPolyFlags = mpImplPolygon->mpFlagAry != NULL;
2105 rOStream << *this
2106 << bHasPolyFlags;
2107
2108 if ( bHasPolyFlags )
2109 rOStream.Write( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
2110 }
2111
2112 // -----------------------------------------------------------------------
2113
Write(SvStream & rOStream) const2114 void Polygon::Write( SvStream& rOStream ) const
2115 {
2116 VersionCompat aCompat( rOStream, STREAM_WRITE, 1 );
2117
2118 ImplWrite( rOStream );
2119 }
2120
2121 // -----------------------------------------------------------------------
2122 // numerical correction method for B2DPolygon
impCorrectContinuity(basegfx::B2DPolygon & roPolygon,sal_uInt32 nIndex,sal_uInt8 nCFlag)2123 void impCorrectContinuity(basegfx::B2DPolygon& roPolygon, sal_uInt32 nIndex, sal_uInt8 nCFlag)
2124 {
2125 const sal_uInt32 nPointCount(roPolygon.count());
2126 OSL_ENSURE(nIndex < nPointCount, "impCorrectContinuity: index access out of range (!)");
2127
2128 if(nIndex < nPointCount && (POLY_SMOOTH == nCFlag || POLY_SYMMTR == nCFlag))
2129 {
2130 if(roPolygon.isPrevControlPointUsed(nIndex) && roPolygon.isNextControlPointUsed(nIndex))
2131 {
2132 // #115917# Patch from osnola (modified, thanks for showing the porblem)
2133 //
2134 // The correction is needed because an integer polygon with control points
2135 // is converted to double precision. When C1 or C2 is used the involved vectors
2136 // may not have the same directions/lengths since these come from integer coordinates
2137 // and may have been snapped to different nearest integer coordinates. The snap error
2138 // is in the range of +-1 in y and y, thus 0.0 <= error <= sqrt(2.0). Nonetheless,
2139 // it needs to be corrected to be able to detect the continuity in this points
2140 // correctly.
2141 //
2142 // We only have the integer data here (already in double precision form, but no mantisses
2143 // used), so the best correction is to use:
2144 //
2145 // for C1: The longest vector since it potentially has best preserved the original vector.
2146 // Even better the sum of the vectors, weighted by their length. This gives the
2147 // normal vector addition to get the vector itself, lengths need to be preserved.
2148 // for C2: The mediated vector(s) since both should be the same, but mirrored
2149
2150 // extract the point and vectors
2151 const basegfx::B2DPoint aPoint(roPolygon.getB2DPoint(nIndex));
2152 const basegfx::B2DVector aNext(roPolygon.getNextControlPoint(nIndex) - aPoint);
2153 const basegfx::B2DVector aPrev(aPoint - roPolygon.getPrevControlPoint(nIndex));
2154
2155 // calculate common direction vector, normalize
2156 const basegfx::B2DVector aDirection(aNext + aPrev);
2157
2158 if(POLY_SMOOTH == nCFlag)
2159 {
2160 // C1: apply common direction vector, preserve individual lengths
2161 const double fInvDirectionLen(1.0 / aDirection.getLength());
2162 roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + (aDirection * (aNext.getLength() * fInvDirectionLen))));
2163 roPolygon.setPrevControlPoint(nIndex, basegfx::B2DPoint(aPoint - (aDirection * (aPrev.getLength() * fInvDirectionLen))));
2164 }
2165 else // POLY_SYMMTR
2166 {
2167 // C2: get mediated length. Taking half of the unnormalized direction would be
2168 // an approximation, but not correct.
2169 const double fMedLength((aNext.getLength() + aPrev.getLength()) * (0.5 / aDirection.getLength()));
2170 const basegfx::B2DVector aScaledDirection(aDirection * fMedLength);
2171
2172 // Bring Direction to correct length and apply
2173 roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + aScaledDirection));
2174 roPolygon.setPrevControlPoint(nIndex, basegfx::B2DPoint(aPoint - aScaledDirection));
2175 }
2176 }
2177 }
2178 }
2179
2180 // -----------------------------------------------------------------------
2181 // convert to basegfx::B2DPolygon and return
getB2DPolygon() const2182 basegfx::B2DPolygon Polygon::getB2DPolygon() const
2183 {
2184 basegfx::B2DPolygon aRetval;
2185 const sal_uInt16 nCount(mpImplPolygon->mnPoints);
2186
2187 if(nCount)
2188 {
2189 if(mpImplPolygon->mpFlagAry)
2190 {
2191 // handling for curves. Add start point
2192 const Point aStartPoint(mpImplPolygon->mpPointAry[0]);
2193 sal_uInt8 nPointFlag(mpImplPolygon->mpFlagAry[0]);
2194 aRetval.append(basegfx::B2DPoint(aStartPoint.X(), aStartPoint.Y()));
2195 Point aControlA, aControlB;
2196
2197 for(sal_uInt16 a(1); a < nCount;)
2198 {
2199 bool bControlA(false);
2200 bool bControlB(false);
2201
2202 if(POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
2203 {
2204 aControlA = mpImplPolygon->mpPointAry[a++];
2205 bControlA = true;
2206 }
2207
2208 if(a < nCount && POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
2209 {
2210 aControlB = mpImplPolygon->mpPointAry[a++];
2211 bControlB = true;
2212 }
2213
2214 // assert invalid polygons
2215 OSL_ENSURE(bControlA == bControlB, "Polygon::getB2DPolygon: Invalid source polygon (!)");
2216
2217 if(a < nCount)
2218 {
2219 const Point aEndPoint(mpImplPolygon->mpPointAry[a]);
2220
2221 if(bControlA)
2222 {
2223 // bezier edge, add
2224 aRetval.appendBezierSegment(
2225 basegfx::B2DPoint(aControlA.X(), aControlA.Y()),
2226 basegfx::B2DPoint(aControlB.X(), aControlB.Y()),
2227 basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
2228
2229 impCorrectContinuity(aRetval, aRetval.count() - 2, nPointFlag);
2230 }
2231 else
2232 {
2233 // no bezier edge, add end point
2234 aRetval.append(basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
2235 }
2236
2237 nPointFlag = mpImplPolygon->mpFlagAry[a++];
2238 }
2239 }
2240
2241 // if exist, remove double first/last points, set closed and correct control points
2242 basegfx::tools::checkClosed(aRetval);
2243
2244 if(aRetval.isClosed())
2245 {
2246 // closeWithGeometryChange did really close, so last point(s) were removed.
2247 // Correct the continuity in the changed point
2248 impCorrectContinuity(aRetval, 0, mpImplPolygon->mpFlagAry[0]);
2249 }
2250 }
2251 else
2252 {
2253 // extra handling for non-curves (most-used case) for speedup
2254 for(sal_uInt16 a(0); a < nCount; a++)
2255 {
2256 // get point and add
2257 const Point aPoint(mpImplPolygon->mpPointAry[a]);
2258 aRetval.append(basegfx::B2DPoint(aPoint.X(), aPoint.Y()));
2259 }
2260
2261 // set closed flag
2262 basegfx::tools::checkClosed(aRetval);
2263 }
2264 }
2265
2266 return aRetval;
2267 }
2268
2269 // -----------------------------------------------------------------------
2270 // constructor to convert from basegfx::B2DPolygon
2271 // #i76891# Needed to change from adding all control points (even for unused
2272 // edges) and creating a fixed-size Polygon in the first run to creating the
2273 // minimal Polygon. This requires a temporary Point- and Flag-Array for curves
2274 // and a memcopy at ImplPolygon creation, but contains no zero-controlpoints
2275 // for straight edges.
Polygon(const basegfx::B2DPolygon & rPolygon)2276 Polygon::Polygon(const basegfx::B2DPolygon& rPolygon)
2277 : mpImplPolygon(0)
2278 {
2279 DBG_CTOR( Polygon, NULL );
2280
2281 const bool bCurve(rPolygon.areControlPointsUsed());
2282 const bool bClosed(rPolygon.isClosed());
2283 sal_uInt32 nB2DLocalCount(rPolygon.count());
2284
2285 if(bCurve)
2286 {
2287 // #127979# Reduce source point count hard to the limit of the tools Polygon
2288 if(nB2DLocalCount > ((0x0000ffff / 3L) - 1L))
2289 {
2290 DBG_ERROR("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
2291 nB2DLocalCount = ((0x0000ffff / 3L) - 1L);
2292 }
2293
2294 // calculate target point count
2295 const sal_uInt32 nLoopCount(bClosed ? nB2DLocalCount : (nB2DLocalCount ? nB2DLocalCount - 1L : 0L ));
2296
2297 if(nLoopCount)
2298 {
2299 // calculate maximum array size and allocate; prepare insert index
2300 const sal_uInt32 nMaxTargetCount((nLoopCount * 3) + 1);
2301 mpImplPolygon = new ImplPolygon(static_cast< sal_uInt16 >(nMaxTargetCount), true);
2302
2303 // prepare insert index and current point
2304 sal_uInt32 nArrayInsert(0);
2305 basegfx::B2DCubicBezier aBezier;
2306 aBezier.setStartPoint(rPolygon.getB2DPoint(0));
2307
2308 for(sal_uInt32 a(0L); a < nLoopCount; a++)
2309 {
2310 // add current point (always) and remember StartPointIndex for evtl. later corrections
2311 const Point aStartPoint(FRound(aBezier.getStartPoint().getX()), FRound(aBezier.getStartPoint().getY()));
2312 const sal_uInt32 nStartPointIndex(nArrayInsert);
2313 mpImplPolygon->mpPointAry[nStartPointIndex] = aStartPoint;
2314 mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_NORMAL;
2315 nArrayInsert++;
2316
2317 // prepare next segment
2318 const sal_uInt32 nNextIndex((a + 1) % nB2DLocalCount);
2319 aBezier.setEndPoint(rPolygon.getB2DPoint(nNextIndex));
2320 aBezier.setControlPointA(rPolygon.getNextControlPoint(a));
2321 aBezier.setControlPointB(rPolygon.getPrevControlPoint(nNextIndex));
2322
2323 if(aBezier.isBezier())
2324 {
2325 // if one is used, add always two control points due to the old schema
2326 mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointA().getX()), FRound(aBezier.getControlPointA().getY()));
2327 mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
2328 nArrayInsert++;
2329
2330 mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointB().getX()), FRound(aBezier.getControlPointB().getY()));
2331 mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
2332 nArrayInsert++;
2333 }
2334
2335 // test continuity with previous control point to set flag value
2336 if(aBezier.getControlPointA() != aBezier.getStartPoint() && (bClosed || a))
2337 {
2338 const basegfx::B2VectorContinuity eCont(rPolygon.getContinuityInPoint(a));
2339
2340 if(basegfx::CONTINUITY_C1 == eCont)
2341 {
2342 mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SMOOTH;
2343 }
2344 else if(basegfx::CONTINUITY_C2 == eCont)
2345 {
2346 mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SYMMTR;
2347 }
2348 }
2349
2350 // prepare next polygon step
2351 aBezier.setStartPoint(aBezier.getEndPoint());
2352 }
2353
2354 if(bClosed)
2355 {
2356 // add first point again as closing point due to old definition
2357 mpImplPolygon->mpPointAry[nArrayInsert] = mpImplPolygon->mpPointAry[0];
2358 mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
2359 nArrayInsert++;
2360 }
2361 else
2362 {
2363 // add last point as closing point
2364 const basegfx::B2DPoint aClosingPoint(rPolygon.getB2DPoint(nB2DLocalCount - 1L));
2365 const Point aEnd(FRound(aClosingPoint.getX()), FRound(aClosingPoint.getY()));
2366 mpImplPolygon->mpPointAry[nArrayInsert] = aEnd;
2367 mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
2368 nArrayInsert++;
2369 }
2370
2371 DBG_ASSERT(nArrayInsert <= nMaxTargetCount, "Polygon::Polygon from basegfx::B2DPolygon: wrong max point count estimation (!)");
2372
2373 if(nArrayInsert != nMaxTargetCount)
2374 {
2375 mpImplPolygon->ImplSetSize(static_cast< sal_uInt16 >(nArrayInsert), true);
2376 }
2377 }
2378 }
2379 else
2380 {
2381 // #127979# Reduce source point count hard to the limit of the tools Polygon
2382 if(nB2DLocalCount > (0x0000ffff - 1L))
2383 {
2384 DBG_ERROR("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
2385 nB2DLocalCount = (0x0000ffff - 1L);
2386 }
2387
2388 if(nB2DLocalCount)
2389 {
2390 // point list creation
2391 const sal_uInt32 nTargetCount(nB2DLocalCount + (bClosed ? 1L : 0L));
2392 mpImplPolygon = new ImplPolygon( static_cast< sal_uInt16 >(nTargetCount) );
2393 sal_uInt16 nIndex(0);
2394
2395 for(sal_uInt32 a(0L); a < nB2DLocalCount; a++)
2396 {
2397 basegfx::B2DPoint aB2DPoint(rPolygon.getB2DPoint(a));
2398 Point aPoint(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY()));
2399 mpImplPolygon->mpPointAry[nIndex++] = aPoint;
2400 }
2401
2402 if(bClosed)
2403 {
2404 // add first point as closing point
2405 mpImplPolygon->mpPointAry[nIndex] = mpImplPolygon->mpPointAry[0];
2406 }
2407 }
2408 }
2409
2410 if(!mpImplPolygon)
2411 {
2412 // no content yet, create empty polygon
2413 mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
2414 }
2415 }
2416
2417 // eof
2418