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