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