Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <osl/endian.h>
21 : #include <tools/bigint.hxx>
22 : #include <tools/debug.hxx>
23 : #include <tools/helpers.hxx>
24 : #include <tools/stream.hxx>
25 : #include <tools/vcompat.hxx>
26 : #include <poly.h>
27 : #include <tools/line.hxx>
28 : #include <tools/vector2d.hxx>
29 : #include <tools/poly.hxx>
30 : #include <basegfx/polygon/b2dpolygon.hxx>
31 : #include <basegfx/point/b2dpoint.hxx>
32 : #include <basegfx/vector/b2dvector.hxx>
33 : #include <basegfx/polygon/b2dpolygontools.hxx>
34 : #include <basegfx/curve/b2dcubicbezier.hxx>
35 :
36 : #include <vector>
37 : #include <iterator>
38 : #include <algorithm>
39 : #include <cstring>
40 : #include <limits.h>
41 : #include <cmath>
42 :
43 : DBG_NAME( Polygon )
44 :
45 : #define EDGE_LEFT 1
46 : #define EDGE_TOP 2
47 : #define EDGE_RIGHT 4
48 : #define EDGE_BOTTOM 8
49 : #define EDGE_HORZ (EDGE_RIGHT | EDGE_LEFT)
50 : #define EDGE_VERT (EDGE_TOP | EDGE_BOTTOM)
51 : #define SMALL_DVALUE 0.0000001
52 : #define FSQRT2 1.4142135623730950488016887242097
53 :
54 : static ImplPolygonData aStaticImplPolygon =
55 : {
56 : NULL, NULL, 0, 0
57 : };
58 :
59 8534 : ImplPolygon::ImplPolygon( sal_uInt16 nInitSize, sal_Bool bFlags )
60 : {
61 8534 : if ( nInitSize )
62 : {
63 8534 : mpPointAry = (Point*)new char[(sal_uIntPtr)nInitSize*sizeof(Point)];
64 8534 : memset( mpPointAry, 0, (sal_uIntPtr)nInitSize*sizeof(Point) );
65 : }
66 : else
67 0 : mpPointAry = NULL;
68 :
69 8534 : if( bFlags )
70 : {
71 234 : mpFlagAry = new sal_uInt8[ nInitSize ];
72 234 : memset( mpFlagAry, 0, nInitSize );
73 : }
74 : else
75 8300 : mpFlagAry = NULL;
76 :
77 8534 : mnRefCount = 1;
78 8534 : mnPoints = nInitSize;
79 8534 : }
80 :
81 2296 : ImplPolygon::ImplPolygon( const ImplPolygon& rImpPoly )
82 : {
83 2296 : if ( rImpPoly.mnPoints )
84 : {
85 2271 : mpPointAry = (Point*)new char[(sal_uIntPtr)rImpPoly.mnPoints*sizeof(Point)];
86 2271 : memcpy( mpPointAry, rImpPoly.mpPointAry, (sal_uIntPtr)rImpPoly.mnPoints*sizeof(Point) );
87 :
88 2271 : if( rImpPoly.mpFlagAry )
89 : {
90 194 : mpFlagAry = new sal_uInt8[ rImpPoly.mnPoints ];
91 194 : memcpy( mpFlagAry, rImpPoly.mpFlagAry, rImpPoly.mnPoints );
92 : }
93 : else
94 2077 : mpFlagAry = NULL;
95 : }
96 : else
97 : {
98 25 : mpPointAry = NULL;
99 25 : mpFlagAry = NULL;
100 : }
101 :
102 2296 : mnRefCount = 1;
103 2296 : mnPoints = rImpPoly.mnPoints;
104 2296 : }
105 :
106 277 : ImplPolygon::ImplPolygon( sal_uInt16 nInitSize, const Point* pInitAry, const sal_uInt8* pInitFlags )
107 : {
108 277 : if ( nInitSize )
109 : {
110 277 : mpPointAry = (Point*)new char[(sal_uIntPtr)nInitSize*sizeof(Point)];
111 277 : memcpy( mpPointAry, pInitAry, (sal_uIntPtr)nInitSize*sizeof( Point ) );
112 :
113 277 : if( pInitFlags )
114 : {
115 184 : mpFlagAry = new sal_uInt8[ nInitSize ];
116 184 : memcpy( mpFlagAry, pInitFlags, nInitSize );
117 : }
118 : else
119 93 : mpFlagAry = NULL;
120 : }
121 : else
122 : {
123 0 : mpPointAry = NULL;
124 0 : mpFlagAry = NULL;
125 : }
126 :
127 277 : mnRefCount = 1;
128 277 : mnPoints = nInitSize;
129 277 : }
130 :
131 11085 : ImplPolygon::~ImplPolygon()
132 : {
133 11085 : if ( mpPointAry )
134 : {
135 11085 : delete[] (char*) mpPointAry;
136 : }
137 :
138 11085 : if( mpFlagAry )
139 628 : delete[] mpFlagAry;
140 11085 : }
141 :
142 11131 : void ImplPolygon::ImplSetSize( sal_uInt16 nNewSize, sal_Bool bResize )
143 : {
144 11131 : if( mnPoints == nNewSize )
145 11131 : return;
146 :
147 : Point* pNewAry;
148 :
149 11131 : if ( nNewSize )
150 : {
151 11131 : pNewAry = (Point*)new char[(sal_uIntPtr)nNewSize*sizeof(Point)];
152 :
153 11131 : if ( bResize )
154 : {
155 : // Alte Punkte kopieren
156 11131 : if ( mnPoints < nNewSize )
157 : {
158 : // Neue Punkte mit 0 initialisieren
159 10971 : memset( pNewAry+mnPoints, 0, (sal_uIntPtr)(nNewSize-mnPoints)*sizeof(Point) );
160 10971 : if ( mpPointAry )
161 10946 : memcpy( pNewAry, mpPointAry, mnPoints*sizeof(Point) );
162 : }
163 : else
164 : {
165 160 : if ( mpPointAry )
166 160 : memcpy( pNewAry, mpPointAry, (sal_uIntPtr)nNewSize*sizeof(Point) );
167 : }
168 : }
169 : }
170 : else
171 0 : pNewAry = NULL;
172 :
173 11131 : if ( mpPointAry )
174 11106 : delete[] (char*) mpPointAry;
175 :
176 : // ggf. FlagArray beruecksichtigen
177 11131 : if( mpFlagAry )
178 : {
179 : sal_uInt8* pNewFlagAry;
180 :
181 359 : if( nNewSize )
182 : {
183 359 : pNewFlagAry = new sal_uInt8[ nNewSize ];
184 :
185 359 : if( bResize )
186 : {
187 : // Alte Flags kopieren
188 359 : if ( mnPoints < nNewSize )
189 : {
190 : // Neue Punkte mit 0 initialisieren
191 207 : memset( pNewFlagAry+mnPoints, 0, nNewSize-mnPoints );
192 207 : memcpy( pNewFlagAry, mpFlagAry, mnPoints );
193 : }
194 : else
195 152 : memcpy( pNewFlagAry, mpFlagAry, nNewSize );
196 : }
197 : }
198 : else
199 0 : pNewFlagAry = NULL;
200 :
201 359 : delete[] mpFlagAry;
202 359 : mpFlagAry = pNewFlagAry;
203 : }
204 :
205 11131 : mpPointAry = pNewAry;
206 11131 : mnPoints = nNewSize;
207 : }
208 :
209 55 : void ImplPolygon::ImplSplit( sal_uInt16 nPos, sal_uInt16 nSpace, ImplPolygon* pInitPoly )
210 : {
211 55 : const sal_uIntPtr nSpaceSize = nSpace * sizeof( Point );
212 :
213 : //Can't fit this in :-(, throw ?
214 55 : if (mnPoints + nSpace > USHRT_MAX)
215 55 : return;
216 :
217 55 : const sal_uInt16 nNewSize = mnPoints + nSpace;
218 :
219 55 : if( nPos >= mnPoints )
220 : {
221 : // Append at the back
222 55 : nPos = mnPoints;
223 55 : ImplSetSize( nNewSize, sal_True );
224 :
225 55 : if( pInitPoly )
226 : {
227 21 : memcpy( mpPointAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
228 :
229 21 : if( pInitPoly->mpFlagAry )
230 16 : memcpy( mpFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
231 : }
232 : }
233 : else
234 : {
235 0 : const sal_uInt16 nSecPos = nPos + nSpace;
236 0 : const sal_uInt16 nRest = mnPoints - nPos;
237 :
238 0 : Point* pNewAry = (Point*) new char[ (sal_uIntPtr) nNewSize * sizeof( Point ) ];
239 :
240 0 : memcpy( pNewAry, mpPointAry, nPos * sizeof( Point ) );
241 :
242 0 : if( pInitPoly )
243 0 : memcpy( pNewAry + nPos, pInitPoly->mpPointAry, nSpaceSize );
244 : else
245 0 : memset( pNewAry + nPos, 0, nSpaceSize );
246 :
247 0 : memcpy( pNewAry + nSecPos, mpPointAry + nPos, nRest * sizeof( Point ) );
248 0 : delete[] (char*) mpPointAry;
249 :
250 : // consider FlagArray
251 0 : if( mpFlagAry )
252 : {
253 0 : sal_uInt8* pNewFlagAry = new sal_uInt8[ nNewSize ];
254 :
255 0 : memcpy( pNewFlagAry, mpFlagAry, nPos );
256 :
257 0 : if( pInitPoly && pInitPoly->mpFlagAry )
258 0 : memcpy( pNewFlagAry + nPos, pInitPoly->mpFlagAry, nSpace );
259 : else
260 0 : memset( pNewFlagAry + nPos, 0, nSpace );
261 :
262 0 : memcpy( pNewFlagAry + nSecPos, mpFlagAry + nPos, nRest );
263 0 : delete[] mpFlagAry;
264 0 : mpFlagAry = pNewFlagAry;
265 : }
266 :
267 0 : mpPointAry = pNewAry;
268 0 : mnPoints = nNewSize;
269 : }
270 : }
271 :
272 662 : void ImplPolygon::ImplCreateFlagArray()
273 : {
274 662 : if( !mpFlagAry )
275 : {
276 32 : mpFlagAry = new sal_uInt8[ mnPoints ];
277 32 : memset( mpFlagAry, 0, mnPoints );
278 : }
279 662 : }
280 :
281 788795 : inline void Polygon::ImplMakeUnique()
282 : {
283 : // copy references if any exist
284 788795 : if ( mpImplPolygon->mnRefCount != 1 )
285 : {
286 2296 : if ( mpImplPolygon->mnRefCount )
287 2271 : mpImplPolygon->mnRefCount--;
288 2296 : mpImplPolygon = new ImplPolygon( *mpImplPolygon );
289 : }
290 788795 : }
291 :
292 0 : inline double ImplGetParameter( const Point& rCenter, const Point& rPt, double fWR, double fHR )
293 : {
294 0 : const long nDX = rPt.X() - rCenter.X();
295 0 : double fAngle = atan2( -rPt.Y() + rCenter.Y(), ( ( nDX == 0L ) ? 0.000000001 : nDX ) );
296 :
297 0 : return atan2(fWR*sin(fAngle), fHR*cos(fAngle));
298 : }
299 :
300 632 : Polygon::Polygon()
301 : {
302 : DBG_CTOR( Polygon, NULL );
303 632 : mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
304 632 : }
305 :
306 4938 : Polygon::Polygon( sal_uInt16 nSize )
307 : {
308 : DBG_CTOR( Polygon, NULL );
309 :
310 4938 : if ( nSize )
311 4935 : mpImplPolygon = new ImplPolygon( nSize );
312 : else
313 3 : mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
314 4938 : }
315 :
316 277 : Polygon::Polygon( sal_uInt16 nPoints, const Point* pPtAry, const sal_uInt8* pFlagAry )
317 : {
318 : DBG_CTOR( Polygon, NULL );
319 :
320 277 : if( nPoints )
321 277 : mpImplPolygon = new ImplPolygon( nPoints, pPtAry, pFlagAry );
322 : else
323 0 : mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
324 277 : }
325 :
326 4848 : Polygon::Polygon( const Polygon& rPoly )
327 : {
328 : DBG_CTOR( Polygon, NULL );
329 : DBG_CHKOBJ( &rPoly, Polygon, NULL );
330 : DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
331 :
332 4848 : mpImplPolygon = rPoly.mpImplPolygon;
333 4848 : if ( mpImplPolygon->mnRefCount )
334 4812 : mpImplPolygon->mnRefCount++;
335 4848 : }
336 :
337 21 : Polygon::Polygon( const Rectangle& rRect )
338 : {
339 : DBG_CTOR( Polygon, NULL );
340 :
341 21 : if ( rRect.IsEmpty() )
342 1 : mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
343 : else
344 : {
345 20 : mpImplPolygon = new ImplPolygon( 5 );
346 20 : mpImplPolygon->mpPointAry[0] = rRect.TopLeft();
347 20 : mpImplPolygon->mpPointAry[1] = rRect.TopRight();
348 20 : mpImplPolygon->mpPointAry[2] = rRect.BottomRight();
349 20 : mpImplPolygon->mpPointAry[3] = rRect.BottomLeft();
350 20 : mpImplPolygon->mpPointAry[4] = rRect.TopLeft();
351 : }
352 21 : }
353 :
354 0 : Polygon::Polygon( const Rectangle& rRect, sal_uIntPtr nHorzRound, sal_uIntPtr nVertRound )
355 : {
356 : DBG_CTOR( Polygon, NULL );
357 :
358 0 : if ( rRect.IsEmpty() )
359 0 : mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
360 : else
361 : {
362 0 : Rectangle aRect( rRect );
363 0 : aRect.Justify(); // SJ: i9140
364 :
365 0 : nHorzRound = Min( nHorzRound, (sal_uIntPtr) labs( aRect.GetWidth() >> 1 ) );
366 0 : nVertRound = Min( nVertRound, (sal_uIntPtr) labs( aRect.GetHeight() >> 1 ) );
367 :
368 0 : if( !nHorzRound && !nVertRound )
369 : {
370 0 : mpImplPolygon = new ImplPolygon( 5 );
371 0 : mpImplPolygon->mpPointAry[0] = aRect.TopLeft();
372 0 : mpImplPolygon->mpPointAry[1] = aRect.TopRight();
373 0 : mpImplPolygon->mpPointAry[2] = aRect.BottomRight();
374 0 : mpImplPolygon->mpPointAry[3] = aRect.BottomLeft();
375 0 : mpImplPolygon->mpPointAry[4] = aRect.TopLeft();
376 : }
377 : else
378 : {
379 0 : const Point aTL( aRect.Left() + nHorzRound, aRect.Top() + nVertRound );
380 0 : const Point aTR( aRect.Right() - nHorzRound, aRect.Top() + nVertRound );
381 0 : const Point aBR( aRect.Right() - nHorzRound, aRect.Bottom() - nVertRound );
382 0 : const Point aBL( aRect.Left() + nHorzRound, aRect.Bottom() - nVertRound );
383 0 : Polygon* pEllipsePoly = new Polygon( Point(), nHorzRound, nVertRound );
384 0 : sal_uInt16 i, nEnd, nSize4 = pEllipsePoly->GetSize() >> 2;
385 :
386 0 : mpImplPolygon = new ImplPolygon( pEllipsePoly->GetSize() + 1 );
387 :
388 0 : const Point* pSrcAry = pEllipsePoly->GetConstPointAry();
389 0 : Point* pDstAry = mpImplPolygon->mpPointAry;
390 :
391 0 : for( i = 0, nEnd = nSize4; i < nEnd; i++ )
392 0 : ( pDstAry[ i ] = pSrcAry[ i ] ) += aTR;
393 :
394 0 : for( nEnd = nEnd + nSize4; i < nEnd; i++ )
395 0 : ( pDstAry[ i ] = pSrcAry[ i ] ) += aTL;
396 :
397 0 : for( nEnd = nEnd + nSize4; i < nEnd; i++ )
398 0 : ( pDstAry[ i ] = pSrcAry[ i ] ) += aBL;
399 :
400 0 : for( nEnd = nEnd + nSize4; i < nEnd; i++ )
401 0 : ( pDstAry[ i ] = pSrcAry[ i ] ) += aBR;
402 :
403 0 : pDstAry[ nEnd ] = pDstAry[ 0 ];
404 0 : delete pEllipsePoly;
405 : }
406 : }
407 0 : }
408 :
409 1 : Polygon::Polygon( const Point& rCenter, long nRadX, long nRadY, sal_uInt16 nPoints )
410 : {
411 : DBG_CTOR( Polygon, NULL );
412 :
413 1 : if( nRadX && nRadY )
414 : {
415 : // Compute default (depends on size)
416 1 : if( !nPoints )
417 : {
418 : nPoints = (sal_uInt16) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
419 1 : sqrt( (double) labs( nRadX * nRadY ) ) ) );
420 :
421 1 : nPoints = (sal_uInt16) MinMax( nPoints, 32, 256 );
422 :
423 1 : if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
424 1 : nPoints >>= 1;
425 : }
426 :
427 : // Ceil number of points until divisible by four
428 1 : mpImplPolygon = new ImplPolygon( nPoints = (nPoints + 3) & ~3 );
429 :
430 : Point* pPt;
431 : sal_uInt16 i;
432 1 : sal_uInt16 nPoints2 = nPoints >> 1;
433 1 : sal_uInt16 nPoints4 = nPoints >> 2;
434 : double nAngle;
435 1 : double nAngleStep = F_PI2 / ( nPoints4 - 1 );
436 :
437 33 : for( i=0, nAngle = 0.0; i < nPoints4; i++, nAngle += nAngleStep )
438 : {
439 32 : long nX = FRound( nRadX * cos( nAngle ) );
440 32 : long nY = FRound( -nRadY * sin( nAngle ) );
441 :
442 32 : pPt = &(mpImplPolygon->mpPointAry[i]);
443 32 : pPt->X() = nX + rCenter.X();
444 32 : pPt->Y() = nY + rCenter.Y();
445 32 : pPt = &(mpImplPolygon->mpPointAry[nPoints2-i-1]);
446 32 : pPt->X() = -nX + rCenter.X();
447 32 : pPt->Y() = nY + rCenter.Y();
448 32 : pPt = &(mpImplPolygon->mpPointAry[i+nPoints2]);
449 32 : pPt->X() = -nX + rCenter.X();
450 32 : pPt->Y() = -nY + rCenter.Y();
451 32 : pPt = &(mpImplPolygon->mpPointAry[nPoints-i-1]);
452 32 : pPt->X() = nX + rCenter.X();
453 32 : pPt->Y() = -nY + rCenter.Y();
454 1 : }
455 : }
456 : else
457 0 : mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
458 1 : }
459 :
460 0 : Polygon::Polygon( const Rectangle& rBound, const Point& rStart, const Point& rEnd,
461 : PolyStyle eStyle, sal_Bool bFullCircle )
462 : {
463 : DBG_CTOR( Polygon, NULL );
464 :
465 0 : const long nWidth = rBound.GetWidth();
466 0 : const long nHeight = rBound.GetHeight();
467 :
468 0 : if( ( nWidth > 1 ) && ( nHeight > 1 ) )
469 : {
470 0 : const Point aCenter( rBound.Center() );
471 0 : const long nRadX = aCenter.X() - rBound.Left();
472 0 : const long nRadY = aCenter.Y() - rBound.Top();
473 : sal_uInt16 nPoints;
474 :
475 : nPoints = (sal_uInt16) ( F_PI * ( 1.5 * ( nRadX + nRadY ) -
476 0 : sqrt( (double) labs( nRadX * nRadY ) ) ) );
477 :
478 0 : nPoints = (sal_uInt16) MinMax( nPoints, 32, 256 );
479 :
480 0 : if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 )
481 0 : nPoints >>= 1;
482 :
483 : // compute threshold
484 0 : const double fRadX = nRadX;
485 0 : const double fRadY = nRadY;
486 0 : const double fCenterX = aCenter.X();
487 0 : const double fCenterY = aCenter.Y();
488 0 : double fStart = ImplGetParameter( aCenter, rStart, fRadX, fRadY );
489 0 : double fEnd = ImplGetParameter( aCenter, rEnd, fRadX, fRadY );
490 0 : double fDiff = fEnd - fStart;
491 : double fStep;
492 : sal_uInt16 nStart;
493 : sal_uInt16 nEnd;
494 :
495 0 : if( fDiff < 0. )
496 0 : fDiff += F_2PI;
497 :
498 0 : if ( bFullCircle )
499 0 : fDiff = F_2PI;
500 :
501 : // Proportionally shrink number of points( fDiff / (2PI) );
502 0 : nPoints = Max( (sal_uInt16) ( ( fDiff * 0.1591549 ) * nPoints ), (sal_uInt16) 16 );
503 0 : fStep = fDiff / ( nPoints - 1 );
504 :
505 0 : if( POLY_PIE == eStyle )
506 : {
507 0 : const Point aCenter2( FRound( fCenterX ), FRound( fCenterY ) );
508 :
509 0 : nStart = 1;
510 0 : nEnd = nPoints + 1;
511 0 : mpImplPolygon = new ImplPolygon( nPoints + 2 );
512 0 : mpImplPolygon->mpPointAry[ 0 ] = aCenter2;
513 0 : mpImplPolygon->mpPointAry[ nEnd ] = aCenter2;
514 : }
515 : else
516 : {
517 0 : mpImplPolygon = new ImplPolygon( ( POLY_CHORD == eStyle ) ? ( nPoints + 1 ) : nPoints );
518 0 : nStart = 0;
519 0 : nEnd = nPoints;
520 : }
521 :
522 0 : for(; nStart < nEnd; nStart++, fStart += fStep )
523 : {
524 0 : Point& rPt = mpImplPolygon->mpPointAry[ nStart ];
525 :
526 0 : rPt.X() = FRound( fCenterX + fRadX * cos( fStart ) );
527 0 : rPt.Y() = FRound( fCenterY - fRadY * sin( fStart ) );
528 : }
529 :
530 0 : if( POLY_CHORD == eStyle )
531 0 : mpImplPolygon->mpPointAry[ nPoints ] = mpImplPolygon->mpPointAry[ 0 ];
532 : }
533 : else
534 0 : mpImplPolygon = (ImplPolygon*) &aStaticImplPolygon;
535 0 : }
536 :
537 0 : Polygon::Polygon( const Point& rBezPt1, const Point& rCtrlPt1,
538 : const Point& rBezPt2, const Point& rCtrlPt2,
539 : sal_uInt16 nPoints )
540 : {
541 : DBG_CTOR( Polygon, NULL );
542 :
543 0 : nPoints = ( 0 == nPoints ) ? 25 : ( ( nPoints < 2 ) ? 2 : nPoints );
544 :
545 0 : const double fInc = 1.0 / ( nPoints - 1 );
546 0 : double fK_1 = 0.0, fK1_1 = 1.0;
547 : double fK_2, fK_3, fK1_2, fK1_3, fK12, fK21;
548 0 : const double fX0 = rBezPt1.X();
549 0 : const double fY0 = rBezPt1.Y();
550 0 : const double fX1 = 3.0 * rCtrlPt1.X();
551 0 : const double fY1 = 3.0 * rCtrlPt1.Y();
552 0 : const double fX2 = 3.0 * rCtrlPt2.X();
553 0 : const double fY2 = 3.0 * rCtrlPt2.Y();
554 0 : const double fX3 = rBezPt2.X();
555 0 : const double fY3 = rBezPt2.Y();
556 :
557 0 : mpImplPolygon = new ImplPolygon( nPoints );
558 :
559 0 : for( sal_uInt16 i = 0; i < nPoints; i++, fK_1 += fInc, fK1_1 -= fInc )
560 : {
561 0 : Point& rPt = mpImplPolygon->mpPointAry[ i ];
562 :
563 0 : fK_2 = fK_1, fK_3 = ( fK_2 *= fK_1 ), fK_3 *= fK_1;
564 0 : fK1_2 = fK1_1, fK1_3 = ( fK1_2 *= fK1_1 ), fK1_3 *= fK1_1;
565 0 : fK12 = fK_1 * fK1_2, fK21 = fK_2 * fK1_1;
566 :
567 0 : rPt.X() = FRound( fK1_3 * fX0 + fK12 * fX1 + fK21 * fX2 + fK_3 * fX3 );
568 0 : rPt.Y() = FRound( fK1_3 * fY0 + fK12 * fY1 + fK21 * fY2 + fK_3 * fY3 );
569 : }
570 0 : }
571 :
572 14279 : Polygon::~Polygon()
573 : {
574 : DBG_DTOR( Polygon, NULL );
575 :
576 : // Remove if refcount == 0, otherwise decrement refcount
577 14279 : if ( mpImplPolygon->mnRefCount )
578 : {
579 14226 : if ( mpImplPolygon->mnRefCount > 1 )
580 4398 : mpImplPolygon->mnRefCount--;
581 : else
582 9828 : delete mpImplPolygon;
583 : }
584 14279 : }
585 :
586 50964 : const Point* Polygon::GetConstPointAry() const
587 : {
588 : DBG_CHKTHIS( Polygon, NULL );
589 50964 : return (Point*)mpImplPolygon->mpPointAry;
590 : }
591 :
592 295 : const sal_uInt8* Polygon::GetConstFlagAry() const
593 : {
594 : DBG_CHKTHIS( Polygon, NULL );
595 295 : return mpImplPolygon->mpFlagAry;
596 : }
597 :
598 12454 : void Polygon::SetPoint( const Point& rPt, sal_uInt16 nPos )
599 : {
600 : DBG_CHKTHIS( Polygon, NULL );
601 : DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
602 : "Polygon::SetPoint(): nPos >= nPoints" );
603 :
604 12454 : ImplMakeUnique();
605 12454 : mpImplPolygon->mpPointAry[nPos] = rPt;
606 12454 : }
607 :
608 646 : void Polygon::SetFlags( sal_uInt16 nPos, PolyFlags eFlags )
609 : {
610 : DBG_CHKTHIS( Polygon, NULL );
611 : DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
612 : "Polygon::SetFlags(): nPos >= nPoints" );
613 :
614 : // we do only want to create the flag array if there
615 : // is at least one flag different to POLY_NORMAL
616 646 : if ( mpImplPolygon || ( eFlags != POLY_NORMAL ) )
617 : {
618 646 : ImplMakeUnique();
619 646 : mpImplPolygon->ImplCreateFlagArray();
620 646 : mpImplPolygon->mpFlagAry[ nPos ] = (sal_uInt8) eFlags;
621 : }
622 646 : }
623 :
624 17370 : const Point& Polygon::GetPoint( sal_uInt16 nPos ) const
625 : {
626 : DBG_CHKTHIS( Polygon, NULL );
627 : DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
628 : "Polygon::GetPoint(): nPos >= nPoints" );
629 :
630 17370 : return mpImplPolygon->mpPointAry[nPos];
631 : }
632 :
633 178 : PolyFlags Polygon::GetFlags( sal_uInt16 nPos ) const
634 : {
635 : DBG_CHKTHIS( Polygon, NULL );
636 : DBG_ASSERT( nPos < mpImplPolygon->mnPoints,
637 : "Polygon::GetFlags(): nPos >= nPoints" );
638 : return( mpImplPolygon->mpFlagAry ?
639 178 : (PolyFlags) mpImplPolygon->mpFlagAry[ nPos ] :
640 356 : POLY_NORMAL );
641 : }
642 :
643 4163 : sal_Bool Polygon::HasFlags() const
644 : {
645 4163 : return mpImplPolygon->mpFlagAry != NULL;
646 : }
647 :
648 0 : sal_Bool Polygon::IsRect() const
649 : {
650 0 : sal_Bool bIsRect = sal_False;
651 0 : if ( mpImplPolygon->mpFlagAry == NULL )
652 : {
653 0 : if ( ( ( mpImplPolygon->mnPoints == 5 ) && ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ 4 ] ) ) ||
654 : ( mpImplPolygon->mnPoints == 4 ) )
655 : {
656 0 : if ( ( mpImplPolygon->mpPointAry[ 0 ].X() == mpImplPolygon->mpPointAry[ 3 ].X() ) &&
657 0 : ( mpImplPolygon->mpPointAry[ 0 ].Y() == mpImplPolygon->mpPointAry[ 1 ].Y() ) &&
658 0 : ( mpImplPolygon->mpPointAry[ 1 ].X() == mpImplPolygon->mpPointAry[ 2 ].X() ) &&
659 0 : ( mpImplPolygon->mpPointAry[ 2 ].Y() == mpImplPolygon->mpPointAry[ 3 ].Y() ) )
660 0 : bIsRect = sal_True;
661 : }
662 : }
663 0 : return bIsRect;
664 : }
665 :
666 10933 : void Polygon::SetSize( sal_uInt16 nNewSize )
667 : {
668 : DBG_CHKTHIS( Polygon, NULL );
669 :
670 10933 : if( nNewSize != mpImplPolygon->mnPoints )
671 : {
672 10924 : ImplMakeUnique();
673 10924 : mpImplPolygon->ImplSetSize( nNewSize );
674 : }
675 10933 : }
676 :
677 90591 : sal_uInt16 Polygon::GetSize() const
678 : {
679 : DBG_CHKTHIS( Polygon, NULL );
680 :
681 90591 : return mpImplPolygon->mnPoints;
682 : }
683 :
684 0 : void Polygon::Clear()
685 : {
686 : DBG_CHKTHIS( Polygon, NULL );
687 :
688 0 : if ( mpImplPolygon->mnRefCount )
689 : {
690 0 : if ( mpImplPolygon->mnRefCount > 1 )
691 0 : mpImplPolygon->mnRefCount--;
692 : else
693 0 : delete mpImplPolygon;
694 : }
695 :
696 0 : mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
697 0 : }
698 :
699 0 : double Polygon::CalcDistance( sal_uInt16 nP1, sal_uInt16 nP2 )
700 : {
701 : DBG_ASSERT( nP1 < mpImplPolygon->mnPoints,
702 : "Polygon::CalcDistance(): nPos1 >= nPoints" );
703 : DBG_ASSERT( nP2 < mpImplPolygon->mnPoints,
704 : "Polygon::CalcDistance(): nPos2 >= nPoints" );
705 :
706 0 : const Point& rP1 = mpImplPolygon->mpPointAry[ nP1 ];
707 0 : const Point& rP2 = mpImplPolygon->mpPointAry[ nP2 ];
708 0 : const double fDx = rP2.X() - rP1.X();
709 0 : const double fDy = rP2.Y() - rP1.Y();
710 :
711 0 : return sqrt( fDx * fDx + fDy * fDy );
712 : }
713 :
714 0 : void Polygon::Optimize( sal_uIntPtr nOptimizeFlags, const PolyOptimizeData* pData )
715 : {
716 : DBG_CHKTHIS( Polygon, NULL );
717 : DBG_ASSERT( !mpImplPolygon->mpFlagAry, "Optimizing could fail with beziers!" );
718 :
719 0 : sal_uInt16 nSize = mpImplPolygon->mnPoints;
720 :
721 0 : if( nOptimizeFlags && nSize )
722 : {
723 0 : if( nOptimizeFlags & POLY_OPTIMIZE_EDGES )
724 : {
725 0 : const Rectangle aBound( GetBoundRect() );
726 0 : const double fArea = ( aBound.GetWidth() + aBound.GetHeight() ) * 0.5;
727 0 : const sal_uInt16 nPercent = pData ? pData->GetPercentValue() : 50;
728 :
729 0 : Optimize( POLY_OPTIMIZE_NO_SAME );
730 0 : ImplReduceEdges( *this, fArea, nPercent );
731 : }
732 0 : else if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE | POLY_OPTIMIZE_NO_SAME ) )
733 : {
734 0 : Polygon aNewPoly;
735 0 : const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
736 : sal_uIntPtr nReduce;
737 :
738 0 : if( nOptimizeFlags & ( POLY_OPTIMIZE_REDUCE ) )
739 0 : nReduce = pData ? pData->GetAbsValue() : 4UL;
740 : else
741 0 : nReduce = 0UL;
742 :
743 0 : while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
744 0 : nSize--;
745 :
746 0 : if( nSize > 1 )
747 : {
748 0 : sal_uInt16 nLast = 0, nNewCount = 1;
749 :
750 0 : aNewPoly.SetSize( nSize );
751 0 : aNewPoly[ 0 ] = rFirst;
752 :
753 0 : for( sal_uInt16 i = 1; i < nSize; i++ )
754 : {
755 0 : if( ( mpImplPolygon->mpPointAry[ i ] != mpImplPolygon->mpPointAry[ nLast ] ) &&
756 0 : ( !nReduce || ( nReduce < (sal_uIntPtr) FRound( CalcDistance( nLast, i ) ) ) ) )
757 : {
758 0 : aNewPoly[ nNewCount++ ] = mpImplPolygon->mpPointAry[ nLast = i ];
759 : }
760 : }
761 :
762 0 : if( nNewCount == 1 )
763 0 : aNewPoly.Clear();
764 : else
765 0 : aNewPoly.SetSize( nNewCount );
766 : }
767 :
768 0 : *this = aNewPoly;
769 : }
770 :
771 0 : nSize = mpImplPolygon->mnPoints;
772 :
773 0 : if( nSize > 1 )
774 : {
775 0 : if( ( nOptimizeFlags & POLY_OPTIMIZE_CLOSE ) &&
776 0 : ( mpImplPolygon->mpPointAry[ 0 ] != mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
777 : {
778 0 : SetSize( mpImplPolygon->mnPoints + 1 );
779 0 : mpImplPolygon->mpPointAry[ mpImplPolygon->mnPoints - 1 ] = mpImplPolygon->mpPointAry[ 0 ];
780 : }
781 0 : else if( ( nOptimizeFlags & POLY_OPTIMIZE_OPEN ) &&
782 0 : ( mpImplPolygon->mpPointAry[ 0 ] == mpImplPolygon->mpPointAry[ nSize - 1 ] ) )
783 : {
784 0 : const Point& rFirst = mpImplPolygon->mpPointAry[ 0 ];
785 :
786 0 : while( nSize && ( mpImplPolygon->mpPointAry[ nSize - 1 ] == rFirst ) )
787 0 : nSize--;
788 :
789 0 : SetSize( nSize );
790 : }
791 : }
792 : }
793 0 : }
794 :
795 :
796 : /** Recursively subdivide cubic bezier curve via deCasteljau.
797 :
798 : @param rPointIter
799 : Output iterator, where the subdivided polylines are written to.
800 :
801 : @param d
802 : Squared difference of curve to a straight line
803 :
804 : @param P*
805 : Exactly four points, interpreted as support and control points of
806 : a cubic bezier curve. Must be in device coordinates, since stop
807 : criterion is based on the following assumption: the device has a
808 : finite resolution, it is thus sufficient to stop subdivision if the
809 : curve does not deviate more than one pixel from a straight line.
810 :
811 : */
812 18121 : static void ImplAdaptiveSubdivide( ::std::back_insert_iterator< ::std::vector< Point > >& rPointIter,
813 : const double old_d2,
814 : int recursionDepth,
815 : const double d2,
816 : const double P1x, const double P1y,
817 : const double P2x, const double P2y,
818 : const double P3x, const double P3y,
819 : const double P4x, const double P4y )
820 : {
821 : // Hard limit on recursion depth, empiric number.
822 : enum {maxRecursionDepth=128};
823 :
824 : // Perform bezier flatness test (lecture notes from R. Schaback,
825 : // Mathematics of Computer-Aided Design, Uni Goettingen, 2000)
826 : //
827 : // ||P(t) - L(t)|| <= max ||b_j - b_0 - j/n(b_n - b_0)||
828 : // 0<=j<=n
829 : //
830 : // What is calculated here is an upper bound to the distance from
831 : // a line through b_0 and b_3 (P1 and P4 in our notation) and the
832 : // curve. We can drop 0 and n from the running indices, since the
833 : // argument of max becomes zero for those cases.
834 18121 : const double fJ1x( P2x - P1x - 1.0/3.0*(P4x - P1x) );
835 18121 : const double fJ1y( P2y - P1y - 1.0/3.0*(P4y - P1y) );
836 18121 : const double fJ2x( P3x - P1x - 2.0/3.0*(P4x - P1x) );
837 18121 : const double fJ2y( P3y - P1y - 2.0/3.0*(P4y - P1y) );
838 : const double distance2( ::std::max( fJ1x*fJ1x + fJ1y*fJ1y,
839 18121 : fJ2x*fJ2x + fJ2y*fJ2y) );
840 :
841 : // stop if error measure does not improve anymore. This is a
842 : // safety guard against floating point inaccuracies.
843 : // stop at recursion level 128. This is a safety guard against
844 : // floating point inaccuracies.
845 : // stop if distance from line is guaranteed to be bounded by d
846 18121 : if( old_d2 > d2 &&
847 : recursionDepth < maxRecursionDepth &&
848 : distance2 >= d2 )
849 : {
850 : // deCasteljau bezier arc, split at t=0.5
851 : // Foley/vanDam, p. 508
852 7961 : const double L1x( P1x ), L1y( P1y );
853 7961 : const double L2x( (P1x + P2x)*0.5 ), L2y( (P1y + P2y)*0.5 );
854 7961 : const double Hx ( (P2x + P3x)*0.5 ), Hy ( (P2y + P3y)*0.5 );
855 7961 : const double L3x( (L2x + Hx)*0.5 ), L3y( (L2y + Hy)*0.5 );
856 7961 : const double R4x( P4x ), R4y( P4y );
857 7961 : const double R3x( (P3x + P4x)*0.5 ), R3y( (P3y + P4y)*0.5 );
858 7961 : const double R2x( (Hx + R3x)*0.5 ), R2y( (Hy + R3y)*0.5 );
859 7961 : const double R1x( (L3x + R2x)*0.5 ), R1y( (L3y + R2y)*0.5 );
860 7961 : const double L4x( R1x ), L4y( R1y );
861 :
862 : // subdivide further
863 7961 : ++recursionDepth;
864 7961 : ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, L1x, L1y, L2x, L2y, L3x, L3y, L4x, L4y);
865 7961 : ImplAdaptiveSubdivide(rPointIter, distance2, recursionDepth, d2, R1x, R1y, R2x, R2y, R3x, R3y, R4x, R4y);
866 : }
867 : else
868 : {
869 : // requested resolution reached.
870 : // Add end points to output iterator.
871 : // order is preserved, since this is so to say depth first traversal.
872 10160 : *rPointIter++ = Point( FRound(P1x), FRound(P1y) );
873 : }
874 18121 : }
875 :
876 619 : void Polygon::AdaptiveSubdivide( Polygon& rResult, const double d ) const
877 : {
878 619 : if( !mpImplPolygon->mpFlagAry )
879 : {
880 393 : rResult = *this;
881 : }
882 : else
883 : {
884 : sal_uInt16 i;
885 226 : sal_uInt16 nPts( GetSize() );
886 226 : ::std::vector< Point > aPoints;
887 226 : aPoints.reserve( nPts );
888 226 : ::std::back_insert_iterator< ::std::vector< Point > > aPointIter( aPoints );
889 :
890 3841 : for(i=0; i<nPts;)
891 : {
892 3389 : if( ( i + 3 ) < nPts )
893 : {
894 2971 : sal_uInt8 P1( mpImplPolygon->mpFlagAry[ i ] );
895 2971 : sal_uInt8 P4( mpImplPolygon->mpFlagAry[ i + 3 ] );
896 :
897 8141 : if( ( POLY_NORMAL == P1 || POLY_SMOOTH == P1 || POLY_SYMMTR == P1 ) &&
898 2971 : ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 1 ] ) &&
899 2199 : ( POLY_CONTROL == mpImplPolygon->mpFlagAry[ i + 2 ] ) &&
900 : ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
901 : {
902 : ImplAdaptiveSubdivide( aPointIter, d*d+1.0, 0, d*d,
903 4398 : mpImplPolygon->mpPointAry[ i ].X(), mpImplPolygon->mpPointAry[ i ].Y(),
904 4398 : mpImplPolygon->mpPointAry[ i+1 ].X(), mpImplPolygon->mpPointAry[ i+1 ].Y(),
905 4398 : mpImplPolygon->mpPointAry[ i+2 ].X(), mpImplPolygon->mpPointAry[ i+2 ].Y(),
906 15393 : mpImplPolygon->mpPointAry[ i+3 ].X(), mpImplPolygon->mpPointAry[ i+3 ].Y() );
907 2199 : i += 3;
908 2199 : continue;
909 : }
910 : }
911 :
912 1190 : *aPointIter++ = mpImplPolygon->mpPointAry[ i++ ];
913 : }
914 :
915 : // fill result polygon
916 226 : rResult = Polygon( (sal_uInt16)aPoints.size() ); // ensure sufficient size for copy
917 226 : ::std::copy(aPoints.begin(), aPoints.end(), rResult.mpImplPolygon->mpPointAry);
918 : }
919 619 : }
920 :
921 0 : void Polygon::ImplReduceEdges( Polygon& rPoly, const double& rArea, sal_uInt16 nPercent )
922 : {
923 0 : const double fBound = 2000.0 * ( 100 - nPercent ) * 0.01;
924 0 : sal_uInt16 nNumNoChange = 0,
925 0 : nNumRuns = 0;
926 :
927 0 : while( nNumNoChange < 2 )
928 : {
929 0 : sal_uInt16 nPntCnt = rPoly.GetSize(), nNewPos = 0;
930 0 : Polygon aNewPoly( nPntCnt );
931 0 : sal_Bool bChangeInThisRun = sal_False;
932 :
933 0 : for( sal_uInt16 n = 0; n < nPntCnt; n++ )
934 : {
935 0 : sal_Bool bDeletePoint = sal_False;
936 :
937 0 : if( ( n + nNumRuns ) % 2 )
938 : {
939 0 : sal_uInt16 nIndPrev = !n ? nPntCnt - 1 : n - 1;
940 0 : sal_uInt16 nIndPrevPrev = !nIndPrev ? nPntCnt - 1 : nIndPrev - 1;
941 0 : sal_uInt16 nIndNext = ( n == nPntCnt-1 ) ? 0 : n + 1;
942 0 : sal_uInt16 nIndNextNext = ( nIndNext == nPntCnt - 1 ) ? 0 : nIndNext + 1;
943 0 : Vector2D aVec1( rPoly[ nIndPrev ] ); aVec1 -= rPoly[ nIndPrevPrev ];
944 0 : Vector2D aVec2( rPoly[ n ] ); aVec2 -= rPoly[ nIndPrev ];
945 0 : Vector2D aVec3( rPoly[ nIndNext ] ); aVec3 -= rPoly[ n ];
946 0 : Vector2D aVec4( rPoly[ nIndNextNext ] ); aVec4 -= rPoly[ nIndNext ];
947 0 : double fDist1 = aVec1.GetLength(), fDist2 = aVec2.GetLength();
948 0 : double fDist3 = aVec3.GetLength(), fDist4 = aVec4.GetLength();
949 0 : double fTurnB = aVec2.Normalize().Scalar( aVec3.Normalize() );
950 :
951 0 : if( fabs( fTurnB ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnB ) > ( 1.0 - SMALL_DVALUE ) )
952 0 : bDeletePoint = sal_True;
953 : else
954 : {
955 0 : Vector2D aVecB( rPoly[ nIndNext ] );
956 0 : double fDistB = ( aVecB -= rPoly[ nIndPrev ] ).GetLength();
957 0 : double fLenWithB = fDist2 + fDist3;
958 0 : double fLenFact = ( fDistB != 0.0 ) ? fLenWithB / fDistB : 1.0;
959 0 : double fTurnPrev = aVec1.Normalize().Scalar( aVec2 );
960 0 : double fTurnNext = aVec3.Scalar( aVec4.Normalize() );
961 : double fGradPrev, fGradB, fGradNext;
962 :
963 0 : if( fabs( fTurnPrev ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnPrev ) > ( 1.0 - SMALL_DVALUE ) )
964 0 : fGradPrev = 0.0;
965 : else
966 0 : fGradPrev = acos( fTurnPrev ) / ( aVec1.IsNegative( aVec2 ) ? -F_PI180 : F_PI180 );
967 :
968 0 : fGradB = acos( fTurnB ) / ( aVec2.IsNegative( aVec3 ) ? -F_PI180 : F_PI180 );
969 :
970 0 : if( fabs( fTurnNext ) < ( 1.0 + SMALL_DVALUE ) && fabs( fTurnNext ) > ( 1.0 - SMALL_DVALUE ) )
971 0 : fGradNext = 0.0;
972 : else
973 0 : fGradNext = acos( fTurnNext ) / ( aVec3.IsNegative( aVec4 ) ? -F_PI180 : F_PI180 );
974 :
975 0 : if( ( fGradPrev > 0.0 && fGradB < 0.0 && fGradNext > 0.0 ) ||
976 : ( fGradPrev < 0.0 && fGradB > 0.0 && fGradNext < 0.0 ) )
977 : {
978 0 : if( ( fLenFact < ( FSQRT2 + SMALL_DVALUE ) ) &&
979 : ( ( ( fDist1 + fDist4 ) / ( fDist2 + fDist3 ) ) * 2000.0 ) > fBound )
980 : {
981 0 : bDeletePoint = sal_True;
982 : }
983 : }
984 : else
985 : {
986 0 : double fRelLen = 1.0 - sqrt( fDistB / rArea );
987 :
988 0 : if( fRelLen < 0.0 )
989 0 : fRelLen = 0.0;
990 0 : else if( fRelLen > 1.0 )
991 0 : fRelLen = 1.0;
992 :
993 0 : if( ( (sal_uInt32) ( ( ( fLenFact - 1.0 ) * 1000000.0 ) + 0.5 ) < fBound ) &&
994 0 : ( fabs( fGradB ) <= ( fRelLen * fBound * 0.01 ) ) )
995 : {
996 0 : bDeletePoint = sal_True;
997 : }
998 0 : }
999 0 : }
1000 : }
1001 :
1002 0 : if( !bDeletePoint )
1003 0 : aNewPoly[ nNewPos++ ] = rPoly[ n ];
1004 : else
1005 0 : bChangeInThisRun = sal_True;
1006 : }
1007 :
1008 0 : if( bChangeInThisRun && nNewPos )
1009 : {
1010 0 : aNewPoly.SetSize( nNewPos );
1011 0 : rPoly = aNewPoly;
1012 0 : nNumNoChange = 0;
1013 : }
1014 : else
1015 0 : nNumNoChange++;
1016 :
1017 0 : nNumRuns++;
1018 0 : }
1019 0 : }
1020 :
1021 266 : void Polygon::Move( long nHorzMove, long nVertMove )
1022 : {
1023 : DBG_CHKTHIS( Polygon, NULL );
1024 :
1025 : // This check is required for DrawEngine
1026 266 : if ( !nHorzMove && !nVertMove )
1027 266 : return;
1028 :
1029 266 : ImplMakeUnique();
1030 :
1031 : // Move points
1032 266 : sal_uInt16 nCount = mpImplPolygon->mnPoints;
1033 7090 : for ( sal_uInt16 i = 0; i < nCount; i++ )
1034 : {
1035 6824 : Point* pPt = &(mpImplPolygon->mpPointAry[i]);
1036 6824 : pPt->X() += nHorzMove;
1037 6824 : pPt->Y() += nVertMove;
1038 : }
1039 : }
1040 :
1041 0 : void Polygon::Translate(const Point& rTrans)
1042 : {
1043 : DBG_CHKTHIS( Polygon, NULL );
1044 0 : ImplMakeUnique();
1045 :
1046 0 : for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1047 0 : mpImplPolygon->mpPointAry[ i ] += rTrans;
1048 0 : }
1049 :
1050 0 : void Polygon::Scale( double fScaleX, double fScaleY )
1051 : {
1052 : DBG_CHKTHIS( Polygon, NULL );
1053 0 : ImplMakeUnique();
1054 :
1055 0 : for ( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1056 : {
1057 0 : Point& rPnt = mpImplPolygon->mpPointAry[i];
1058 0 : rPnt.X() = (long) ( fScaleX * rPnt.X() );
1059 0 : rPnt.Y() = (long) ( fScaleY * rPnt.Y() );
1060 : }
1061 0 : }
1062 :
1063 95125 : void Polygon::Rotate( const Point& rCenter, sal_uInt16 nAngle10 )
1064 : {
1065 : DBG_CHKTHIS( Polygon, NULL );
1066 95125 : nAngle10 %= 3600;
1067 :
1068 95125 : if( nAngle10 )
1069 : {
1070 71604 : const double fAngle = F_PI1800 * nAngle10;
1071 71604 : Rotate( rCenter, sin( fAngle ), cos( fAngle ) );
1072 : }
1073 95125 : }
1074 :
1075 71604 : void Polygon::Rotate( const Point& rCenter, double fSin, double fCos )
1076 : {
1077 : DBG_CHKTHIS( Polygon, NULL );
1078 71604 : ImplMakeUnique();
1079 :
1080 : long nX, nY;
1081 71604 : long nCenterX = rCenter.X();
1082 71604 : long nCenterY = rCenter.Y();
1083 :
1084 216036 : for( sal_uInt16 i = 0, nCount = mpImplPolygon->mnPoints; i < nCount; i++ )
1085 : {
1086 144432 : Point& rPt = mpImplPolygon->mpPointAry[ i ];
1087 :
1088 144432 : nX = rPt.X() - nCenterX;
1089 144432 : nY = rPt.Y() - nCenterY;
1090 144432 : rPt.X() = (long) FRound( fCos * nX + fSin * nY ) + nCenterX;
1091 144432 : rPt.Y() = -(long) FRound( fSin * nX - fCos * nY ) + nCenterY;
1092 : }
1093 71604 : }
1094 :
1095 0 : class ImplPointFilter
1096 : {
1097 : public:
1098 : virtual void LastPoint() = 0;
1099 : virtual void Input( const Point& rPoint ) = 0;
1100 :
1101 : protected:
1102 0 : ~ImplPointFilter() {}
1103 : };
1104 :
1105 : class ImplPolygonPointFilter : public ImplPointFilter
1106 : {
1107 : public:
1108 : ImplPolygon* mpPoly; // Don't remove, assigned by polygon
1109 : sal_uInt16 mnSize;
1110 :
1111 0 : ImplPolygonPointFilter( sal_uInt16 nDestSize ) :
1112 0 : mnSize( 0 )
1113 : {
1114 0 : mpPoly = new ImplPolygon( nDestSize );
1115 0 : }
1116 :
1117 0 : virtual ~ImplPolygonPointFilter() {}
1118 :
1119 : virtual void LastPoint();
1120 : virtual void Input( const Point& rPoint );
1121 : };
1122 :
1123 0 : void ImplPolygonPointFilter::Input( const Point& rPoint )
1124 : {
1125 0 : if ( !mnSize || (rPoint != mpPoly->mpPointAry[mnSize-1]) )
1126 : {
1127 0 : mnSize++;
1128 0 : if ( mnSize > mpPoly->mnPoints )
1129 0 : mpPoly->ImplSetSize( mnSize );
1130 0 : mpPoly->mpPointAry[mnSize-1] = rPoint;
1131 : }
1132 0 : }
1133 :
1134 0 : void ImplPolygonPointFilter::LastPoint()
1135 : {
1136 0 : if ( mnSize < mpPoly->mnPoints )
1137 0 : mpPoly->ImplSetSize( mnSize );
1138 0 : };
1139 :
1140 : class ImplEdgePointFilter : public ImplPointFilter
1141 : {
1142 : Point maFirstPoint;
1143 : Point maLastPoint;
1144 : ImplPointFilter& mrNextFilter;
1145 : const long mnLow;
1146 : const long mnHigh;
1147 : const int mnEdge;
1148 : int mnLastOutside;
1149 : sal_Bool mbFirst;
1150 :
1151 : public:
1152 0 : ImplEdgePointFilter( int nEdge, long nLow, long nHigh,
1153 : ImplPointFilter& rNextFilter ) :
1154 : mrNextFilter( rNextFilter ),
1155 : mnLow( nLow ),
1156 : mnHigh( nHigh ),
1157 : mnEdge( nEdge ),
1158 0 : mbFirst( sal_True )
1159 : {
1160 0 : }
1161 :
1162 0 : virtual ~ImplEdgePointFilter() {}
1163 :
1164 : Point EdgeSection( const Point& rPoint, int nEdge ) const;
1165 : int VisibleSide( const Point& rPoint ) const;
1166 0 : int IsPolygon() const
1167 0 : { return maFirstPoint == maLastPoint; }
1168 :
1169 : virtual void Input( const Point& rPoint );
1170 : virtual void LastPoint();
1171 : };
1172 :
1173 0 : inline int ImplEdgePointFilter::VisibleSide( const Point& rPoint ) const
1174 : {
1175 0 : if ( mnEdge & EDGE_HORZ )
1176 : {
1177 0 : return rPoint.X() < mnLow ? EDGE_LEFT :
1178 0 : rPoint.X() > mnHigh ? EDGE_RIGHT : 0;
1179 : }
1180 : else
1181 : {
1182 0 : return rPoint.Y() < mnLow ? EDGE_TOP :
1183 0 : rPoint.Y() > mnHigh ? EDGE_BOTTOM : 0;
1184 : }
1185 : }
1186 :
1187 0 : Point ImplEdgePointFilter::EdgeSection( const Point& rPoint, int nEdge ) const
1188 : {
1189 0 : long lx = maLastPoint.X();
1190 0 : long ly = maLastPoint.Y();
1191 0 : long md = rPoint.X() - lx;
1192 0 : long mn = rPoint.Y() - ly;
1193 : long nNewX;
1194 : long nNewY;
1195 :
1196 0 : if ( nEdge & EDGE_VERT )
1197 : {
1198 0 : nNewY = (nEdge == EDGE_TOP) ? mnLow : mnHigh;
1199 0 : long dy = nNewY - ly;
1200 0 : if ( !md )
1201 0 : nNewX = lx;
1202 0 : else if ( (LONG_MAX / Abs(md)) >= Abs(dy) )
1203 0 : nNewX = (dy * md) / mn + lx;
1204 : else
1205 : {
1206 0 : BigInt ady = dy;
1207 0 : ady *= md;
1208 0 : if( ady.IsNeg() )
1209 0 : if( mn < 0 )
1210 0 : ady += mn/2;
1211 : else
1212 0 : ady -= (mn-1)/2;
1213 : else
1214 0 : if( mn < 0 )
1215 0 : ady -= (mn+1)/2;
1216 : else
1217 0 : ady += mn/2;
1218 0 : ady /= mn;
1219 0 : nNewX = (long)ady + lx;
1220 : }
1221 : }
1222 : else
1223 : {
1224 0 : nNewX = (nEdge == EDGE_LEFT) ? mnLow : mnHigh;
1225 0 : long dx = nNewX - lx;
1226 0 : if ( !mn )
1227 0 : nNewY = ly;
1228 0 : else if ( (LONG_MAX / Abs(mn)) >= Abs(dx) )
1229 0 : nNewY = (dx * mn) / md + ly;
1230 : else
1231 : {
1232 0 : BigInt adx = dx;
1233 0 : adx *= mn;
1234 0 : if( adx.IsNeg() )
1235 0 : if( md < 0 )
1236 0 : adx += md/2;
1237 : else
1238 0 : adx -= (md-1)/2;
1239 : else
1240 0 : if( md < 0 )
1241 0 : adx -= (md+1)/2;
1242 : else
1243 0 : adx += md/2;
1244 0 : adx /= md;
1245 0 : nNewY = (long)adx + ly;
1246 : }
1247 : }
1248 :
1249 0 : return Point( nNewX, nNewY );
1250 : }
1251 :
1252 0 : void ImplEdgePointFilter::Input( const Point& rPoint )
1253 : {
1254 0 : int nOutside = VisibleSide( rPoint );
1255 :
1256 0 : if ( mbFirst )
1257 : {
1258 0 : maFirstPoint = rPoint;
1259 0 : mbFirst = sal_False;
1260 0 : if ( !nOutside )
1261 0 : mrNextFilter.Input( rPoint );
1262 : }
1263 0 : else if ( rPoint == maLastPoint )
1264 0 : return;
1265 0 : else if ( !nOutside )
1266 : {
1267 0 : if ( mnLastOutside )
1268 0 : mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1269 0 : mrNextFilter.Input( rPoint );
1270 : }
1271 0 : else if ( !mnLastOutside )
1272 0 : mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1273 0 : else if ( nOutside != mnLastOutside )
1274 : {
1275 0 : mrNextFilter.Input( EdgeSection( rPoint, mnLastOutside ) );
1276 0 : mrNextFilter.Input( EdgeSection( rPoint, nOutside ) );
1277 : }
1278 :
1279 0 : maLastPoint = rPoint;
1280 0 : mnLastOutside = nOutside;
1281 : }
1282 :
1283 0 : void ImplEdgePointFilter::LastPoint()
1284 : {
1285 0 : if ( !mbFirst )
1286 : {
1287 0 : int nOutside = VisibleSide( maFirstPoint );
1288 :
1289 0 : if ( nOutside != mnLastOutside )
1290 0 : Input( maFirstPoint );
1291 0 : mrNextFilter.LastPoint();
1292 : }
1293 0 : }
1294 :
1295 0 : void Polygon::Clip( const Rectangle& rRect, sal_Bool bPolygon )
1296 : {
1297 : // #105251# Justify rect befor edge filtering
1298 0 : Rectangle aJustifiedRect( rRect );
1299 0 : aJustifiedRect.Justify();
1300 :
1301 0 : sal_uInt16 nSourceSize = mpImplPolygon->mnPoints;
1302 0 : ImplPolygonPointFilter aPolygon( nSourceSize );
1303 0 : ImplEdgePointFilter aHorzFilter( EDGE_HORZ, aJustifiedRect.Left(), aJustifiedRect.Right(),
1304 0 : aPolygon );
1305 0 : ImplEdgePointFilter aVertFilter( EDGE_VERT, aJustifiedRect.Top(), aJustifiedRect.Bottom(),
1306 0 : aHorzFilter );
1307 :
1308 0 : for ( sal_uInt16 i = 0; i < nSourceSize; i++ )
1309 0 : aVertFilter.Input( mpImplPolygon->mpPointAry[i] );
1310 0 : if ( bPolygon || aVertFilter.IsPolygon() )
1311 0 : aVertFilter.LastPoint();
1312 : else
1313 0 : aPolygon.LastPoint();
1314 :
1315 : // Delete old ImpPolygon-data and assign from ImpPolygonPointFilter
1316 0 : if ( mpImplPolygon->mnRefCount )
1317 : {
1318 0 : if ( mpImplPolygon->mnRefCount > 1 )
1319 0 : mpImplPolygon->mnRefCount--;
1320 : else
1321 0 : delete mpImplPolygon;
1322 : }
1323 0 : mpImplPolygon = aPolygon.mpPoly;
1324 0 : }
1325 :
1326 23 : Rectangle Polygon::GetBoundRect() const
1327 : {
1328 : DBG_CHKTHIS( Polygon, NULL );
1329 : // Removing the assert. Bezier curves have the attribute that each single
1330 : // curve segment defined by four points can not exit the four-point polygon
1331 : // defined by that points. This allows to say that the curve segment can also
1332 : // never leave the Range of it's defining points.
1333 : // The result is that Polygon::GetBoundRect() may not create the minimal
1334 : // BoundRect of the Polygon (to get that, use basegfx::B2DPolygon classes),
1335 : // but will always create a valid BoundRect, at least as long as this method
1336 : // 'blindly' travels over all points, including control points.
1337 : //
1338 : // DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetBoundRect could fail with beziers!" );
1339 :
1340 23 : sal_uInt16 nCount = mpImplPolygon->mnPoints;
1341 23 : if( ! nCount )
1342 1 : return Rectangle();
1343 :
1344 : long nXMin, nXMax, nYMin, nYMax;
1345 :
1346 22 : const Point* pPt = &(mpImplPolygon->mpPointAry[0]);
1347 22 : nXMin = nXMax = pPt->X();
1348 22 : nYMin = nYMax = pPt->Y();
1349 :
1350 362 : for ( sal_uInt16 i = 0; i < nCount; i++ )
1351 : {
1352 340 : pPt = &(mpImplPolygon->mpPointAry[i]);
1353 :
1354 340 : if ( pPt->X() < nXMin )
1355 36 : nXMin = pPt->X();
1356 340 : if ( pPt->X() > nXMax )
1357 37 : nXMax = pPt->X();
1358 340 : if ( pPt->Y() < nYMin )
1359 34 : nYMin = pPt->Y();
1360 340 : if ( pPt->Y() > nYMax )
1361 29 : nYMax = pPt->Y();
1362 : }
1363 :
1364 22 : return Rectangle( nXMin, nYMin, nXMax, nYMax );
1365 : }
1366 :
1367 0 : double Polygon::GetSignedArea() const
1368 : {
1369 : DBG_CHKTHIS( Polygon, NULL );
1370 : DBG_ASSERT( !mpImplPolygon->mpFlagAry, "GetArea could fail with beziers!" );
1371 :
1372 0 : double fArea = 0.0;
1373 :
1374 0 : if( mpImplPolygon->mnPoints > 2 )
1375 : {
1376 0 : const sal_uInt16 nCount1 = mpImplPolygon->mnPoints - 1;
1377 :
1378 0 : for( sal_uInt16 i = 0; i < nCount1; )
1379 : {
1380 0 : const Point& rPt = mpImplPolygon->mpPointAry[ i ];
1381 0 : const Point& rPt1 = mpImplPolygon->mpPointAry[ ++i ];
1382 0 : fArea += ( rPt.X() - rPt1.X() ) * ( rPt.Y() + rPt1.Y() );
1383 : }
1384 :
1385 0 : const Point& rPt = mpImplPolygon->mpPointAry[ nCount1 ];
1386 0 : const Point& rPt0 = mpImplPolygon->mpPointAry[ 0 ];
1387 0 : fArea += ( rPt.X() - rPt0.X() ) * ( rPt.Y() + rPt0.Y() );
1388 : }
1389 :
1390 0 : return fArea;
1391 : }
1392 :
1393 0 : sal_Bool Polygon::IsInside( const Point& rPoint ) const
1394 : {
1395 : DBG_CHKTHIS( Polygon, NULL );
1396 : DBG_ASSERT( !mpImplPolygon->mpFlagAry, "IsInside could fail with beziers!" );
1397 :
1398 0 : const Rectangle aBound( GetBoundRect() );
1399 0 : const Line aLine( rPoint, Point( aBound.Right() + 100L, rPoint.Y() ) );
1400 0 : sal_uInt16 nCount = mpImplPolygon->mnPoints;
1401 0 : sal_uInt16 nPCounter = 0;
1402 :
1403 0 : if ( ( nCount > 2 ) && aBound.IsInside( rPoint ) )
1404 : {
1405 0 : Point aPt1( mpImplPolygon->mpPointAry[ 0 ] );
1406 0 : Point aIntersection;
1407 0 : Point aLastIntersection;
1408 :
1409 0 : while ( ( aPt1 == mpImplPolygon->mpPointAry[ nCount - 1 ] ) && ( nCount > 3 ) )
1410 0 : nCount--;
1411 :
1412 0 : for ( sal_uInt16 i = 1; i <= nCount; i++ )
1413 : {
1414 0 : const Point& rPt2 = mpImplPolygon->mpPointAry[ ( i < nCount ) ? i : 0 ];
1415 :
1416 0 : if ( aLine.Intersection( Line( aPt1, rPt2 ), aIntersection ) )
1417 : {
1418 : // This avoids insertion of double intersections
1419 0 : if ( nPCounter )
1420 : {
1421 0 : if ( aIntersection != aLastIntersection )
1422 : {
1423 0 : aLastIntersection = aIntersection;
1424 0 : nPCounter++;
1425 : }
1426 : }
1427 : else
1428 : {
1429 0 : aLastIntersection = aIntersection;
1430 0 : nPCounter++;
1431 : }
1432 : }
1433 :
1434 0 : aPt1 = rPt2;
1435 : }
1436 : }
1437 :
1438 : // is inside, if number of intersection points is odd
1439 0 : return ( ( nPCounter & 1 ) == 1 );
1440 : }
1441 :
1442 0 : sal_Bool Polygon::IsRightOrientated() const
1443 : {
1444 : DBG_CHKTHIS( Polygon, NULL );
1445 0 : return GetSignedArea() >= 0.0;
1446 : }
1447 :
1448 34 : void Polygon::Insert( sal_uInt16 nPos, const Point& rPt, PolyFlags eFlags )
1449 : {
1450 : DBG_CHKTHIS( Polygon, NULL );
1451 34 : ImplMakeUnique();
1452 :
1453 34 : if( nPos >= mpImplPolygon->mnPoints )
1454 34 : nPos = mpImplPolygon->mnPoints;
1455 :
1456 34 : mpImplPolygon->ImplSplit( nPos, 1 );
1457 34 : mpImplPolygon->mpPointAry[ nPos ] = rPt;
1458 :
1459 34 : if( POLY_NORMAL != eFlags )
1460 : {
1461 0 : mpImplPolygon->ImplCreateFlagArray();
1462 0 : mpImplPolygon->mpFlagAry[ nPos ] = (sal_uInt8) eFlags;
1463 : }
1464 34 : }
1465 :
1466 21 : void Polygon::Insert( sal_uInt16 nPos, const Polygon& rPoly )
1467 : {
1468 : DBG_CHKTHIS( Polygon, NULL );
1469 21 : const sal_uInt16 nInsertCount = rPoly.mpImplPolygon->mnPoints;
1470 :
1471 21 : if( nInsertCount )
1472 : {
1473 21 : ImplMakeUnique();
1474 :
1475 21 : if( nPos >= mpImplPolygon->mnPoints )
1476 21 : nPos = mpImplPolygon->mnPoints;
1477 :
1478 21 : if( rPoly.mpImplPolygon->mpFlagAry )
1479 16 : mpImplPolygon->ImplCreateFlagArray();
1480 :
1481 21 : mpImplPolygon->ImplSplit( nPos, nInsertCount, rPoly.mpImplPolygon );
1482 : }
1483 21 : }
1484 :
1485 692846 : Point& Polygon::operator[]( sal_uInt16 nPos )
1486 : {
1487 : DBG_CHKTHIS( Polygon, NULL );
1488 : DBG_ASSERT( nPos < mpImplPolygon->mnPoints, "Polygon::[]: nPos >= nPoints" );
1489 :
1490 692846 : ImplMakeUnique();
1491 692846 : return mpImplPolygon->mpPointAry[nPos];
1492 : }
1493 :
1494 2070 : Polygon& Polygon::operator=( const Polygon& rPoly )
1495 : {
1496 : DBG_CHKTHIS( Polygon, NULL );
1497 : DBG_CHKOBJ( &rPoly, Polygon, NULL );
1498 : DBG_ASSERT( rPoly.mpImplPolygon->mnRefCount < 0xFFFFFFFE, "Polygon: RefCount overflow" );
1499 :
1500 : // Increase refcounter before assigning
1501 : // Note: RefCount == 0 for static objects
1502 2070 : if ( rPoly.mpImplPolygon->mnRefCount )
1503 2058 : rPoly.mpImplPolygon->mnRefCount++;
1504 :
1505 : // Delete if recount == 0, otherwise decrement
1506 2070 : if ( mpImplPolygon->mnRefCount )
1507 : {
1508 1458 : if ( mpImplPolygon->mnRefCount > 1 )
1509 201 : mpImplPolygon->mnRefCount--;
1510 : else
1511 1257 : delete mpImplPolygon;
1512 : }
1513 :
1514 2070 : mpImplPolygon = rPoly.mpImplPolygon;
1515 2070 : return *this;
1516 : }
1517 :
1518 0 : sal_Bool Polygon::operator==( const Polygon& rPoly ) const
1519 : {
1520 : DBG_CHKTHIS( Polygon, NULL );
1521 : DBG_CHKOBJ( &rPoly, Polygon, NULL );
1522 :
1523 0 : if ( (rPoly.mpImplPolygon == mpImplPolygon) )
1524 0 : return sal_True;
1525 : else
1526 0 : return sal_False;
1527 : }
1528 :
1529 0 : sal_Bool Polygon::IsEqual( const Polygon& rPoly ) const
1530 : {
1531 0 : sal_Bool bIsEqual = sal_True;
1532 : sal_uInt16 i;
1533 0 : if ( GetSize() != rPoly.GetSize() )
1534 0 : bIsEqual = sal_False;
1535 : else
1536 : {
1537 0 : for ( i = 0; i < GetSize(); i++ )
1538 : {
1539 0 : if ( ( GetPoint( i ) != rPoly.GetPoint( i ) ) ||
1540 0 : ( GetFlags( i ) != rPoly.GetFlags( i ) ) )
1541 : {
1542 0 : bIsEqual = sal_False;
1543 0 : break;
1544 : }
1545 : }
1546 : }
1547 0 : return bIsEqual;
1548 : }
1549 :
1550 0 : SvStream& operator>>( SvStream& rIStream, Polygon& rPoly )
1551 : {
1552 : DBG_CHKOBJ( &rPoly, Polygon, NULL );
1553 : DBG_ASSERTWARNING( rIStream.GetVersion(), "Polygon::>> - Solar-Version not set on rIStream" );
1554 :
1555 : sal_uInt16 i;
1556 : sal_uInt16 nPoints;
1557 :
1558 : // read all points and create array
1559 0 : rIStream >> nPoints;
1560 0 : if ( rPoly.mpImplPolygon->mnRefCount != 1 )
1561 : {
1562 0 : if ( rPoly.mpImplPolygon->mnRefCount )
1563 0 : rPoly.mpImplPolygon->mnRefCount--;
1564 0 : rPoly.mpImplPolygon = new ImplPolygon( nPoints );
1565 : }
1566 : else
1567 0 : rPoly.mpImplPolygon->ImplSetSize( nPoints, sal_False );
1568 :
1569 : {
1570 : // Determine whether we need to write through operators
1571 : #if (SAL_TYPES_SIZEOFLONG) != 4
1572 : if ( 1 )
1573 : #else
1574 : #ifdef OSL_BIGENDIAN
1575 : if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
1576 : #else
1577 0 : if ( rIStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
1578 : #endif
1579 : #endif
1580 : {
1581 0 : for( i = 0; i < nPoints; i++ )
1582 : {
1583 : //fdo#39428 SvStream no longer supports operator>>(long&)
1584 0 : sal_Int32 nTmpX(0), nTmpY(0);
1585 0 : rIStream >> nTmpX >> nTmpY;
1586 0 : rPoly.mpImplPolygon->mpPointAry[i].X() = nTmpX;
1587 0 : rPoly.mpImplPolygon->mpPointAry[i].Y() = nTmpY;
1588 : }
1589 : }
1590 : else
1591 0 : rIStream.Read( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
1592 : }
1593 :
1594 0 : return rIStream;
1595 : }
1596 :
1597 488 : SvStream& operator<<( SvStream& rOStream, const Polygon& rPoly )
1598 : {
1599 : DBG_CHKOBJ( &rPoly, Polygon, NULL );
1600 : DBG_ASSERTWARNING( rOStream.GetVersion(), "Polygon::<< - Solar-Version not set on rOStream" );
1601 :
1602 : sal_uInt16 i;
1603 488 : sal_uInt16 nPoints = rPoly.GetSize();
1604 :
1605 : // Write number of points
1606 488 : rOStream << nPoints;
1607 :
1608 : {
1609 : // Determine whether we need to write through operators
1610 : #if (SAL_TYPES_SIZEOFLONG) != 4
1611 : if ( 1 )
1612 : #else
1613 : #ifdef OSL_BIGENDIAN
1614 : if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_BIGENDIAN )
1615 : #else
1616 488 : if ( rOStream.GetNumberFormatInt() != NUMBERFORMAT_INT_LITTLEENDIAN )
1617 : #endif
1618 : #endif
1619 : {
1620 0 : for( i = 0; i < nPoints; i++ )
1621 : {
1622 : //fdo#39428 SvStream no longer supports operator<<(long)
1623 0 : rOStream << sal::static_int_cast<sal_Int32>( rPoly.mpImplPolygon->mpPointAry[i].X() )
1624 0 : << sal::static_int_cast<sal_Int32>( rPoly.mpImplPolygon->mpPointAry[i].Y() );
1625 : }
1626 : }
1627 : else
1628 : {
1629 488 : if ( nPoints )
1630 479 : rOStream.Write( rPoly.mpImplPolygon->mpPointAry, nPoints*sizeof(Point) );
1631 : }
1632 : }
1633 :
1634 488 : return rOStream;
1635 : }
1636 :
1637 0 : void Polygon::ImplRead( SvStream& rIStream )
1638 : {
1639 : sal_uInt8 bHasPolyFlags;
1640 :
1641 0 : rIStream >> *this
1642 0 : >> bHasPolyFlags;
1643 :
1644 0 : if ( bHasPolyFlags )
1645 : {
1646 0 : mpImplPolygon->mpFlagAry = new sal_uInt8[ mpImplPolygon->mnPoints ];
1647 0 : rIStream.Read( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
1648 : }
1649 0 : }
1650 :
1651 0 : void Polygon::Read( SvStream& rIStream )
1652 : {
1653 0 : VersionCompat aCompat( rIStream, STREAM_READ );
1654 :
1655 0 : ImplRead( rIStream );
1656 0 : }
1657 :
1658 66 : void Polygon::ImplWrite( SvStream& rOStream ) const
1659 : {
1660 66 : sal_uInt8 bHasPolyFlags = mpImplPolygon->mpFlagAry != NULL;
1661 66 : rOStream << *this
1662 132 : << bHasPolyFlags;
1663 :
1664 66 : if ( bHasPolyFlags )
1665 52 : rOStream.Write( mpImplPolygon->mpFlagAry, mpImplPolygon->mnPoints );
1666 66 : }
1667 :
1668 38 : void Polygon::Write( SvStream& rOStream ) const
1669 : {
1670 38 : VersionCompat aCompat( rOStream, STREAM_WRITE, 1 );
1671 :
1672 38 : ImplWrite( rOStream );
1673 38 : }
1674 :
1675 : // #i74631# numerical correction method for B2DPolygon
1676 2093 : void impCorrectContinuity(basegfx::B2DPolygon& roPolygon, sal_uInt32 nIndex, sal_uInt8 nCFlag)
1677 : {
1678 2093 : const sal_uInt32 nPointCount(roPolygon.count());
1679 : OSL_ENSURE(nIndex < nPointCount, "impCorrectContinuity: index access out of range (!)");
1680 :
1681 2093 : if(nIndex < nPointCount && (POLY_SMOOTH == nCFlag || POLY_SYMMTR == nCFlag))
1682 : {
1683 0 : if(roPolygon.isPrevControlPointUsed(nIndex) && roPolygon.isNextControlPointUsed(nIndex))
1684 : {
1685 0 : const basegfx::B2DPoint aPoint(roPolygon.getB2DPoint(nIndex));
1686 :
1687 0 : if(POLY_SMOOTH == nCFlag)
1688 : {
1689 : // C1: apply inverse direction of prev to next, keep length of next
1690 0 : const basegfx::B2DVector aOriginalNext(roPolygon.getNextControlPoint(nIndex) - aPoint);
1691 0 : basegfx::B2DVector aNewNext(aPoint - roPolygon.getPrevControlPoint(nIndex));
1692 :
1693 0 : aNewNext.setLength(aOriginalNext.getLength());
1694 0 : roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + aNewNext));
1695 : }
1696 : else // POLY_SYMMTR
1697 : {
1698 : // C2: apply inverse control point to next
1699 0 : roPolygon.setNextControlPoint(nIndex, (2.0 * aPoint) - roPolygon.getPrevControlPoint(nIndex));
1700 0 : }
1701 : }
1702 : }
1703 2093 : }
1704 :
1705 : // convert to basegfx::B2DPolygon and return
1706 301 : basegfx::B2DPolygon Polygon::getB2DPolygon() const
1707 : {
1708 301 : basegfx::B2DPolygon aRetval;
1709 301 : const sal_uInt16 nCount(mpImplPolygon->mnPoints);
1710 :
1711 301 : if(nCount)
1712 : {
1713 298 : if(mpImplPolygon->mpFlagAry)
1714 : {
1715 : // handling for curves. Add start point
1716 200 : const Point aStartPoint(mpImplPolygon->mpPointAry[0]);
1717 200 : sal_uInt8 nPointFlag(mpImplPolygon->mpFlagAry[0]);
1718 200 : aRetval.append(basegfx::B2DPoint(aStartPoint.X(), aStartPoint.Y()));
1719 200 : Point aControlA, aControlB;
1720 :
1721 3199 : for(sal_uInt16 a(1); a < nCount;)
1722 : {
1723 2799 : bool bControlA(false);
1724 2799 : bool bControlB(false);
1725 :
1726 2799 : if(POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
1727 : {
1728 1893 : aControlA = mpImplPolygon->mpPointAry[a++];
1729 1893 : bControlA = true;
1730 : }
1731 :
1732 2799 : if(a < nCount && POLY_CONTROL == mpImplPolygon->mpFlagAry[a])
1733 : {
1734 1893 : aControlB = mpImplPolygon->mpPointAry[a++];
1735 1893 : bControlB = true;
1736 : }
1737 :
1738 : // assert invalid polygons
1739 : OSL_ENSURE(bControlA == bControlB, "Polygon::getB2DPolygon: Invalid source polygon (!)");
1740 : (void)bControlB;
1741 :
1742 2799 : if(a < nCount)
1743 : {
1744 2799 : const Point aEndPoint(mpImplPolygon->mpPointAry[a]);
1745 :
1746 2799 : if(bControlA)
1747 : {
1748 : // bezier edge, add
1749 : aRetval.appendBezierSegment(
1750 3786 : basegfx::B2DPoint(aControlA.X(), aControlA.Y()),
1751 3786 : basegfx::B2DPoint(aControlB.X(), aControlB.Y()),
1752 9465 : basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
1753 :
1754 1893 : impCorrectContinuity(aRetval, aRetval.count() - 2, nPointFlag);
1755 : }
1756 : else
1757 : {
1758 : // no bezier edge, add end point
1759 906 : aRetval.append(basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y()));
1760 : }
1761 :
1762 2799 : nPointFlag = mpImplPolygon->mpFlagAry[a++];
1763 : }
1764 : }
1765 :
1766 : // if exist, remove double first/last points, set closed and correct control points
1767 200 : basegfx::tools::checkClosed(aRetval);
1768 :
1769 200 : if(aRetval.isClosed())
1770 : {
1771 : // closeWithGeometryChange did really close, so last point(s) were removed.
1772 : // Correct the continuity in the changed point
1773 200 : impCorrectContinuity(aRetval, 0, mpImplPolygon->mpFlagAry[0]);
1774 : }
1775 : }
1776 : else
1777 : {
1778 : // extra handling for non-curves (most-used case) for speedup
1779 732 : for(sal_uInt16 a(0); a < nCount; a++)
1780 : {
1781 : // get point and add
1782 634 : const Point aPoint(mpImplPolygon->mpPointAry[a]);
1783 634 : aRetval.append(basegfx::B2DPoint(aPoint.X(), aPoint.Y()));
1784 : }
1785 :
1786 : // set closed flag
1787 98 : basegfx::tools::checkClosed(aRetval);
1788 : }
1789 : }
1790 :
1791 301 : return aRetval;
1792 : }
1793 :
1794 : // constructor to convert from basegfx::B2DPolygon
1795 : // #i76891# Needed to change from adding all control points (even for unused
1796 : // edges) and creating a fixed-size Polygon in the first run to creating the
1797 : // minimal Polygon. This requires a temporary Point- and Flag-Array for curves
1798 : // and a memcopy at ImplPolygon creation, but contains no zero-controlpoints
1799 : // for straight edges.
1800 3587 : Polygon::Polygon(const basegfx::B2DPolygon& rPolygon)
1801 3587 : : mpImplPolygon(0)
1802 : {
1803 : DBG_CTOR( Polygon, NULL );
1804 :
1805 3587 : const bool bCurve(rPolygon.areControlPointsUsed());
1806 3587 : const bool bClosed(rPolygon.isClosed());
1807 3587 : sal_uInt32 nB2DLocalCount(rPolygon.count());
1808 :
1809 3587 : if(bCurve)
1810 : {
1811 : // #127979# Reduce source point count hard to the limit of the tools Polygon
1812 234 : if(nB2DLocalCount > ((0x0000ffff / 3L) - 1L))
1813 : {
1814 : OSL_FAIL("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
1815 0 : nB2DLocalCount = ((0x0000ffff / 3L) - 1L);
1816 : }
1817 :
1818 : // calculate target point count
1819 234 : const sal_uInt32 nLoopCount(bClosed ? nB2DLocalCount : (nB2DLocalCount ? nB2DLocalCount - 1L : 0L ));
1820 :
1821 234 : if(nLoopCount)
1822 : {
1823 : // calculate maximum array size and allocate; prepare insert index
1824 234 : const sal_uInt32 nMaxTargetCount((nLoopCount * 3) + 1);
1825 234 : mpImplPolygon = new ImplPolygon(static_cast< sal_uInt16 >(nMaxTargetCount), true);
1826 :
1827 : // prepare insert index and current point
1828 234 : sal_uInt32 nArrayInsert(0);
1829 234 : basegfx::B2DCubicBezier aBezier;
1830 234 : aBezier.setStartPoint(rPolygon.getB2DPoint(0));
1831 :
1832 3477 : for(sal_uInt32 a(0L); a < nLoopCount; a++)
1833 : {
1834 : // add current point (always) and remember StartPointIndex for evtl. later corrections
1835 3243 : const Point aStartPoint(FRound(aBezier.getStartPoint().getX()), FRound(aBezier.getStartPoint().getY()));
1836 3243 : const sal_uInt32 nStartPointIndex(nArrayInsert);
1837 3243 : mpImplPolygon->mpPointAry[nStartPointIndex] = aStartPoint;
1838 3243 : mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_NORMAL;
1839 3243 : nArrayInsert++;
1840 :
1841 : // prepare next segment
1842 3243 : const sal_uInt32 nNextIndex((a + 1) % nB2DLocalCount);
1843 3243 : aBezier.setEndPoint(rPolygon.getB2DPoint(nNextIndex));
1844 3243 : aBezier.setControlPointA(rPolygon.getNextControlPoint(a));
1845 3243 : aBezier.setControlPointB(rPolygon.getPrevControlPoint(nNextIndex));
1846 :
1847 3243 : if(aBezier.isBezier())
1848 : {
1849 : // if one is used, add always two control points due to the old schema
1850 2257 : mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointA().getX()), FRound(aBezier.getControlPointA().getY()));
1851 2257 : mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
1852 2257 : nArrayInsert++;
1853 :
1854 2257 : mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointB().getX()), FRound(aBezier.getControlPointB().getY()));
1855 2257 : mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_CONTROL;
1856 2257 : nArrayInsert++;
1857 : }
1858 :
1859 : // test continuity with previous control point to set flag value
1860 3243 : if(aBezier.getControlPointA() != aBezier.getStartPoint() && (bClosed || a))
1861 : {
1862 2245 : const basegfx::B2VectorContinuity eCont(rPolygon.getContinuityInPoint(a));
1863 :
1864 2245 : if(basegfx::CONTINUITY_C1 == eCont)
1865 : {
1866 871 : mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SMOOTH;
1867 : }
1868 1374 : else if(basegfx::CONTINUITY_C2 == eCont)
1869 : {
1870 21 : mpImplPolygon->mpFlagAry[nStartPointIndex] = (sal_uInt8)POLY_SYMMTR;
1871 : }
1872 : }
1873 :
1874 : // prepare next polygon step
1875 3243 : aBezier.setStartPoint(aBezier.getEndPoint());
1876 : }
1877 :
1878 234 : if(bClosed)
1879 : {
1880 : // add first point again as closing point due to old definition
1881 228 : mpImplPolygon->mpPointAry[nArrayInsert] = mpImplPolygon->mpPointAry[0];
1882 228 : mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
1883 228 : nArrayInsert++;
1884 : }
1885 : else
1886 : {
1887 : // add last point as closing point
1888 6 : const basegfx::B2DPoint aClosingPoint(rPolygon.getB2DPoint(nB2DLocalCount - 1L));
1889 6 : const Point aEnd(FRound(aClosingPoint.getX()), FRound(aClosingPoint.getY()));
1890 6 : mpImplPolygon->mpPointAry[nArrayInsert] = aEnd;
1891 6 : mpImplPolygon->mpFlagAry[nArrayInsert] = (sal_uInt8)POLY_NORMAL;
1892 6 : nArrayInsert++;
1893 : }
1894 :
1895 : DBG_ASSERT(nArrayInsert <= nMaxTargetCount, "Polygon::Polygon from basegfx::B2DPolygon: wrong max point count estimation (!)");
1896 :
1897 234 : if(nArrayInsert != nMaxTargetCount)
1898 : {
1899 152 : mpImplPolygon->ImplSetSize(static_cast< sal_uInt16 >(nArrayInsert), true);
1900 234 : }
1901 : }
1902 : }
1903 : else
1904 : {
1905 : // #127979# Reduce source point count hard to the limit of the tools Polygon
1906 3353 : if(nB2DLocalCount > (0x0000ffff - 1L))
1907 : {
1908 : OSL_FAIL("Polygon::Polygon: Too many points in given B2DPolygon, need to reduce hard to maximum of tools Polygon (!)");
1909 0 : nB2DLocalCount = (0x0000ffff - 1L);
1910 : }
1911 :
1912 3353 : if(nB2DLocalCount)
1913 : {
1914 : // point list creation
1915 3344 : const sal_uInt32 nTargetCount(nB2DLocalCount + (bClosed ? 1L : 0L));
1916 3344 : mpImplPolygon = new ImplPolygon( static_cast< sal_uInt16 >(nTargetCount) );
1917 3344 : sal_uInt16 nIndex(0);
1918 :
1919 14896 : for(sal_uInt32 a(0L); a < nB2DLocalCount; a++)
1920 : {
1921 11552 : basegfx::B2DPoint aB2DPoint(rPolygon.getB2DPoint(a));
1922 11552 : Point aPoint(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY()));
1923 11552 : mpImplPolygon->mpPointAry[nIndex++] = aPoint;
1924 11552 : }
1925 :
1926 3344 : if(bClosed)
1927 : {
1928 : // add first point as closing point
1929 319 : mpImplPolygon->mpPointAry[nIndex] = mpImplPolygon->mpPointAry[0];
1930 : }
1931 : }
1932 : }
1933 :
1934 3587 : if(!mpImplPolygon)
1935 : {
1936 : // no content yet, create empty polygon
1937 9 : mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon);
1938 : }
1939 3587 : }
1940 :
1941 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|