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