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