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/stream.hxx>
22 : #include <tools/debug.hxx>
23 : #include <tools/poly.hxx>
24 : #include <tools/helpers.hxx>
25 : #include <tools/gen.hxx>
26 :
27 : #include <svx/xpoly.hxx>
28 : #include "xpolyimp.hxx"
29 : #include <basegfx/polygon/b2dpolygon.hxx>
30 : #include <basegfx/point/b2dpoint.hxx>
31 : #include <basegfx/vector/b2dvector.hxx>
32 : #include <basegfx/polygon/b2dpolygontools.hxx>
33 : #include <basegfx/range/b2drange.hxx>
34 : #include <basegfx/numeric/ftools.hxx>
35 :
36 :
37 1315 : ImpXPolygon::ImpXPolygon(sal_uInt16 nInitSize, sal_uInt16 _nResize)
38 : : pPointAry(NULL)
39 : , pFlagAry(NULL)
40 : , pOldPointAry(NULL)
41 : , bDeleteOldPoints(false)
42 : , nSize(0)
43 : , nResize(_nResize)
44 : , nPoints(0)
45 1315 : , nRefCount(1)
46 : {
47 1315 : Resize(nInitSize);
48 1315 : }
49 :
50 11 : ImpXPolygon::ImpXPolygon( const ImpXPolygon& rImpXPoly )
51 : : pPointAry(NULL)
52 : , pFlagAry(NULL)
53 : , pOldPointAry(NULL)
54 : , bDeleteOldPoints(false)
55 : , nSize(0)
56 : , nResize(rImpXPoly.nResize)
57 : , nPoints(0)
58 11 : , nRefCount(1)
59 : {
60 11 : ( (ImpXPolygon&) rImpXPoly ).CheckPointDelete();
61 :
62 11 : Resize( rImpXPoly.nSize );
63 :
64 : // copy
65 11 : nPoints = rImpXPoly.nPoints;
66 11 : memcpy( pPointAry, rImpXPoly.pPointAry, nSize*sizeof( Point ) );
67 11 : memcpy( pFlagAry, rImpXPoly.pFlagAry, nSize );
68 11 : }
69 :
70 1326 : ImpXPolygon::~ImpXPolygon()
71 : {
72 1326 : delete[] reinterpret_cast<char*>(pPointAry);
73 1326 : delete[] pFlagAry;
74 1326 : if ( bDeleteOldPoints )
75 0 : delete[] reinterpret_cast<char*>(pOldPointAry);
76 1326 : }
77 :
78 0 : bool ImpXPolygon::operator==(const ImpXPolygon& rImpXPoly) const
79 : {
80 0 : return nPoints==rImpXPoly.nPoints &&
81 0 : (nPoints==0 ||
82 0 : (memcmp(pPointAry,rImpXPoly.pPointAry,nPoints*sizeof(Point))==0 &&
83 0 : memcmp(pFlagAry,rImpXPoly.pFlagAry,nPoints)==0));
84 : }
85 :
86 : /** Change polygon size
87 : *
88 : * @param nNewSize the new size of the polygon
89 : * @param bDeletePoints if FALSE, do not delete the point array directly but
90 : * wait for the next call before doing so. This prevents
91 : * errors with XPoly[n] = XPoly[0] where a resize might
92 : * destroy the right side point array too early.
93 : */
94 1326 : void ImpXPolygon::Resize( sal_uInt16 nNewSize, bool bDeletePoints )
95 : {
96 1326 : if( nNewSize == nSize )
97 1326 : return;
98 :
99 1326 : sal_uInt8* pOldFlagAry = pFlagAry;
100 1326 : sal_uInt16 nOldSize = nSize;
101 :
102 1326 : CheckPointDelete();
103 1326 : pOldPointAry = pPointAry;
104 :
105 : // Round the new size to a multiple of nResize, if
106 : // the object was not newly created (nSize != 0)
107 1326 : if ( nSize != 0 && nNewSize > nSize )
108 : {
109 : DBG_ASSERT(nResize, "Trying to resize but nResize = 0 !");
110 0 : nNewSize = nSize + ((nNewSize-nSize-1) / nResize + 1) * nResize;
111 : }
112 : // create point array
113 1326 : nSize = nNewSize;
114 1326 : pPointAry = reinterpret_cast<Point*>(new char[ nSize*sizeof( Point ) ]);
115 1326 : memset( pPointAry, 0, nSize*sizeof( Point ) );
116 :
117 : // create flag array
118 1326 : pFlagAry = new sal_uInt8[ nSize ];
119 1326 : memset( pFlagAry, 0, nSize );
120 :
121 : // copy if needed
122 1326 : if( nOldSize )
123 : {
124 0 : if( nOldSize < nSize )
125 : {
126 0 : memcpy( pPointAry, pOldPointAry, nOldSize*sizeof( Point ) );
127 0 : memcpy( pFlagAry, pOldFlagAry, nOldSize );
128 : }
129 : else
130 : {
131 0 : memcpy( pPointAry, pOldPointAry, nSize*sizeof( Point ) );
132 0 : memcpy( pFlagAry, pOldFlagAry, nSize );
133 :
134 : // adjust number of valid points
135 0 : if( nPoints > nSize )
136 0 : nPoints = nSize;
137 : }
138 0 : if ( bDeletePoints ) delete[] reinterpret_cast<char*>(pOldPointAry);
139 0 : else bDeleteOldPoints = true;
140 0 : delete[] pOldFlagAry;
141 : }
142 : }
143 :
144 170 : void ImpXPolygon::InsertSpace( sal_uInt16 nPos, sal_uInt16 nCount )
145 : {
146 170 : CheckPointDelete();
147 :
148 170 : if ( nPos > nPoints )
149 0 : nPos = nPoints;
150 :
151 : // if the polygon is too small than enlarge it
152 170 : if( (nPoints + nCount) > nSize )
153 0 : Resize( nPoints + nCount );
154 :
155 : // If the insert is not at the last position, move everything after backwards
156 170 : if( nPos < nPoints )
157 : {
158 0 : sal_uInt16 nMove = nPoints - nPos;
159 0 : memmove( &pPointAry[nPos+nCount], &pPointAry[nPos],
160 0 : nMove * sizeof(Point) );
161 0 : memmove( &pFlagAry[nPos+nCount], &pFlagAry[nPos], nMove );
162 : }
163 170 : memset( &pPointAry[nPos], 0, nCount * sizeof( Point ) );
164 170 : memset( &pFlagAry [nPos], 0, nCount );
165 :
166 170 : nPoints = nPoints + nCount;
167 170 : }
168 :
169 66 : void ImpXPolygon::Remove( sal_uInt16 nPos, sal_uInt16 nCount )
170 : {
171 66 : CheckPointDelete();
172 :
173 66 : if( (nPos + nCount) <= nPoints )
174 : {
175 66 : sal_uInt16 nMove = nPoints - nPos - nCount;
176 :
177 66 : if( nMove )
178 : {
179 20 : memmove( &pPointAry[nPos], &pPointAry[nPos+nCount],
180 30 : nMove * sizeof(Point) );
181 10 : memmove( &pFlagAry[nPos], &pFlagAry[nPos+nCount], nMove );
182 : }
183 66 : memset( &pPointAry[nPoints - nCount], 0, nCount * sizeof( Point ) );
184 66 : memset( &pFlagAry [nPoints - nCount], 0, nCount );
185 66 : nPoints = nPoints - nCount;
186 : }
187 66 : }
188 :
189 998 : XPolygon::XPolygon( sal_uInt16 nSize, sal_uInt16 nResize )
190 : {
191 998 : pImpXPolygon = new ImpXPolygon( nSize, nResize );
192 998 : }
193 :
194 1101 : XPolygon::XPolygon( const XPolygon& rXPoly )
195 : {
196 1101 : pImpXPolygon = rXPoly.pImpXPolygon;
197 1101 : pImpXPolygon->nRefCount++;
198 1101 : }
199 :
200 : /// create a XPolygon out of a standard polygon
201 1 : XPolygon::XPolygon( const Polygon& rPoly )
202 : {
203 :
204 1 : sal_uInt16 nSize = rPoly.GetSize();
205 1 : pImpXPolygon = new ImpXPolygon( nSize );
206 1 : pImpXPolygon->nPoints = nSize;
207 :
208 3 : for( sal_uInt16 i = 0; i < nSize; i++ )
209 : {
210 2 : pImpXPolygon->pPointAry[i] = rPoly[i];
211 2 : pImpXPolygon->pFlagAry[i] = (sal_uInt8) rPoly.GetFlags( i );
212 : }
213 1 : }
214 :
215 : /// create a rectangle (also with rounded corners) as a Bézier polygon
216 15 : XPolygon::XPolygon(const Rectangle& rRect, long nRx, long nRy)
217 : {
218 15 : pImpXPolygon = new ImpXPolygon(17);
219 15 : long nWh = (rRect.GetWidth() - 1) / 2;
220 15 : long nHh = (rRect.GetHeight() - 1) / 2;
221 :
222 15 : if ( nRx > nWh ) nRx = nWh;
223 15 : if ( nRy > nHh ) nRy = nHh;
224 :
225 : // negate Rx => circle clockwise
226 15 : nRx = -nRx;
227 :
228 : // factor for control points of the Bézier curve: 8/3 * (sin(45g) - 0.5)
229 15 : long nXHdl = (long)(0.552284749 * nRx);
230 15 : long nYHdl = (long)(0.552284749 * nRy);
231 15 : sal_uInt16 nPos = 0;
232 :
233 15 : if ( nRx && nRy )
234 : {
235 2 : Point aCenter;
236 :
237 10 : for (sal_uInt16 nQuad = 0; nQuad < 4; nQuad++)
238 : {
239 8 : switch ( nQuad )
240 : {
241 2 : case 0: aCenter = rRect.TopLeft();
242 2 : aCenter.X() -= nRx;
243 2 : aCenter.Y() += nRy;
244 2 : break;
245 2 : case 1: aCenter = rRect.TopRight();
246 2 : aCenter.X() += nRx;
247 2 : aCenter.Y() += nRy;
248 2 : break;
249 2 : case 2: aCenter = rRect.BottomRight();
250 2 : aCenter.X() += nRx;
251 2 : aCenter.Y() -= nRy;
252 2 : break;
253 2 : case 3: aCenter = rRect.BottomLeft();
254 2 : aCenter.X() -= nRx;
255 2 : aCenter.Y() -= nRy;
256 2 : break;
257 : }
258 8 : GenBezArc(aCenter, nRx, nRy, nXHdl, nYHdl, 0, 900, nQuad, nPos);
259 8 : pImpXPolygon->pFlagAry[nPos ] = (sal_uInt8) XPOLY_SMOOTH;
260 8 : pImpXPolygon->pFlagAry[nPos+3] = (sal_uInt8) XPOLY_SMOOTH;
261 8 : nPos += 4;
262 2 : }
263 : }
264 : else
265 : {
266 13 : pImpXPolygon->pPointAry[nPos++] = rRect.TopLeft();
267 13 : pImpXPolygon->pPointAry[nPos++] = rRect.TopRight();
268 13 : pImpXPolygon->pPointAry[nPos++] = rRect.BottomRight();
269 13 : pImpXPolygon->pPointAry[nPos++] = rRect.BottomLeft();
270 : }
271 15 : pImpXPolygon->pPointAry[nPos] = pImpXPolygon->pPointAry[0];
272 15 : pImpXPolygon->nPoints = nPos + 1;
273 15 : }
274 :
275 : /// create a ellipse (curve) as Bézier polygon
276 0 : XPolygon::XPolygon(const Point& rCenter, long nRx, long nRy,
277 : sal_uInt16 nStartAngle, sal_uInt16 nEndAngle, bool bClose)
278 : {
279 0 : pImpXPolygon = new ImpXPolygon(17);
280 :
281 0 : nStartAngle %= 3600;
282 0 : if ( nEndAngle > 3600 ) nEndAngle %= 3600;
283 0 : bool bFull = (nStartAngle == 0 && nEndAngle == 3600);
284 :
285 : // factor for control points of the Bézier curve: 8/3 * (sin(45g) - 0.5)
286 0 : long nXHdl = (long)(0.552284749 * nRx);
287 0 : long nYHdl = (long)(0.552284749 * nRy);
288 0 : sal_uInt16 nPos = 0;
289 0 : bool bLoopEnd = false;
290 :
291 0 : do
292 : {
293 : sal_uInt16 nA1, nA2;
294 0 : sal_uInt16 nQuad = nStartAngle / 900;
295 0 : if ( nQuad == 4 ) nQuad = 0;
296 0 : bLoopEnd = CheckAngles(nStartAngle, nEndAngle, nA1, nA2);
297 0 : GenBezArc(rCenter, nRx, nRy, nXHdl, nYHdl, nA1, nA2, nQuad, nPos);
298 0 : nPos += 3;
299 0 : if ( !bLoopEnd )
300 0 : pImpXPolygon->pFlagAry[nPos] = (sal_uInt8) XPOLY_SMOOTH;
301 :
302 0 : } while ( !bLoopEnd );
303 :
304 : // if not a full circle than connect edges with center point if necessary
305 0 : if ( !bFull && bClose )
306 0 : pImpXPolygon->pPointAry[++nPos] = rCenter;
307 :
308 0 : if ( bFull )
309 : {
310 0 : pImpXPolygon->pFlagAry[0 ] = (sal_uInt8) XPOLY_SMOOTH;
311 0 : pImpXPolygon->pFlagAry[nPos] = (sal_uInt8) XPOLY_SMOOTH;
312 : }
313 0 : pImpXPolygon->nPoints = nPos + 1;
314 0 : }
315 :
316 2416 : XPolygon::~XPolygon()
317 : {
318 2416 : if( pImpXPolygon->nRefCount > 1 )
319 1216 : pImpXPolygon->nRefCount--;
320 : else
321 1200 : delete pImpXPolygon;
322 2416 : }
323 :
324 : /// check reference counter and decouple if > 1
325 2916 : void XPolygon::CheckReference()
326 : {
327 2916 : if( pImpXPolygon->nRefCount > 1 )
328 : {
329 11 : pImpXPolygon->nRefCount--;
330 11 : pImpXPolygon = new ImpXPolygon( *pImpXPolygon );
331 : }
332 2916 : }
333 :
334 0 : void XPolygon::SetPointCount( sal_uInt16 nPoints )
335 : {
336 0 : pImpXPolygon->CheckPointDelete();
337 0 : CheckReference();
338 :
339 0 : if( pImpXPolygon->nSize < nPoints )
340 0 : pImpXPolygon->Resize( nPoints );
341 :
342 0 : if ( nPoints < pImpXPolygon->nPoints )
343 : {
344 0 : sal_uInt16 nSize = pImpXPolygon->nPoints - nPoints;
345 0 : memset( &pImpXPolygon->pPointAry[nPoints], 0, nSize * sizeof( Point ) );
346 0 : memset( &pImpXPolygon->pFlagAry [nPoints], 0, nSize );
347 : }
348 0 : pImpXPolygon->nPoints = nPoints;
349 0 : }
350 :
351 1 : sal_uInt16 XPolygon::GetSize() const
352 : {
353 1 : pImpXPolygon->CheckPointDelete();
354 1 : return pImpXPolygon->nSize;
355 : }
356 :
357 862 : sal_uInt16 XPolygon::GetPointCount() const
358 : {
359 862 : pImpXPolygon->CheckPointDelete();
360 862 : return pImpXPolygon->nPoints;
361 : }
362 :
363 170 : void XPolygon::Insert( sal_uInt16 nPos, const Point& rPt, XPolyFlags eFlags )
364 : {
365 170 : CheckReference();
366 170 : if (nPos>pImpXPolygon->nPoints) nPos=pImpXPolygon->nPoints;
367 170 : pImpXPolygon->InsertSpace( nPos, 1 );
368 170 : pImpXPolygon->pPointAry[nPos] = rPt;
369 170 : pImpXPolygon->pFlagAry[nPos] = (sal_uInt8)eFlags;
370 170 : }
371 :
372 0 : void XPolygon::Insert( sal_uInt16 nPos, const XPolygon& rXPoly )
373 : {
374 0 : CheckReference();
375 0 : if (nPos>pImpXPolygon->nPoints) nPos=pImpXPolygon->nPoints;
376 :
377 0 : sal_uInt16 nPoints = rXPoly.GetPointCount();
378 :
379 0 : pImpXPolygon->InsertSpace( nPos, nPoints );
380 :
381 0 : memcpy( &(pImpXPolygon->pPointAry[nPos]),
382 : rXPoly.pImpXPolygon->pPointAry,
383 0 : nPoints*sizeof( Point ) );
384 0 : memcpy( &(pImpXPolygon->pFlagAry[nPos]),
385 : rXPoly.pImpXPolygon->pFlagAry,
386 0 : nPoints );
387 0 : }
388 :
389 66 : void XPolygon::Remove( sal_uInt16 nPos, sal_uInt16 nCount )
390 : {
391 66 : CheckReference();
392 66 : pImpXPolygon->Remove( nPos, nCount );
393 66 : }
394 :
395 0 : void XPolygon::Move( long nHorzMove, long nVertMove )
396 : {
397 0 : if ( !nHorzMove && !nVertMove )
398 0 : return;
399 :
400 0 : CheckReference();
401 :
402 : // move points
403 0 : sal_uInt16 nCount = pImpXPolygon->nPoints;
404 0 : for ( sal_uInt16 i = 0; i < nCount; i++ )
405 : {
406 0 : Point* pPt = &(pImpXPolygon->pPointAry[i]);
407 0 : pPt->X() += nHorzMove;
408 0 : pPt->Y() += nVertMove;
409 : }
410 : }
411 :
412 194 : Rectangle XPolygon::GetBoundRect() const
413 : {
414 194 : pImpXPolygon->CheckPointDelete();
415 194 : Rectangle aRetval;
416 :
417 194 : if(pImpXPolygon->nPoints)
418 : {
419 : // #i37709#
420 : // For historical reasons the control points are not part of the
421 : // BoundRect. This makes it necessary to subdivide the polygon to
422 : // get a relatively correct BoundRect. Numerically, this is not
423 : // correct and never was.
424 :
425 193 : const basegfx::B2DRange aPolygonRange(basegfx::tools::getRange(getB2DPolygon()));
426 : aRetval = Rectangle(
427 : FRound(aPolygonRange.getMinX()), FRound(aPolygonRange.getMinY()),
428 193 : FRound(aPolygonRange.getMaxX()), FRound(aPolygonRange.getMaxY()));
429 : }
430 :
431 194 : return aRetval;
432 : }
433 :
434 863 : const Point& XPolygon::operator[]( sal_uInt16 nPos ) const
435 : {
436 : DBG_ASSERT(nPos < pImpXPolygon->nPoints, "Ungueltiger Index bei const-Arrayzugriff auf XPolygon");
437 :
438 863 : pImpXPolygon->CheckPointDelete();
439 863 : return pImpXPolygon->pPointAry[nPos];
440 : }
441 :
442 2580 : Point& XPolygon::operator[]( sal_uInt16 nPos )
443 : {
444 2580 : pImpXPolygon->CheckPointDelete();
445 2580 : CheckReference();
446 :
447 2580 : if( nPos >= pImpXPolygon->nSize )
448 : {
449 : DBG_ASSERT(pImpXPolygon->nResize, "Ungueltiger Index bei Arrayzugriff auf XPolygon");
450 0 : pImpXPolygon->Resize(nPos + 1, false);
451 : }
452 2580 : if( nPos >= pImpXPolygon->nPoints )
453 1797 : pImpXPolygon->nPoints = nPos + 1;
454 :
455 2580 : return pImpXPolygon->pPointAry[nPos];
456 : }
457 :
458 126 : XPolygon& XPolygon::operator=( const XPolygon& rXPoly )
459 : {
460 126 : if (this == &rXPoly)
461 0 : return *this;
462 :
463 126 : pImpXPolygon->CheckPointDelete();
464 :
465 126 : rXPoly.pImpXPolygon->nRefCount++;
466 :
467 126 : if( pImpXPolygon->nRefCount > 1 )
468 0 : pImpXPolygon->nRefCount--;
469 : else
470 126 : delete pImpXPolygon;
471 :
472 126 : pImpXPolygon = rXPoly.pImpXPolygon;
473 126 : return *this;
474 : }
475 :
476 0 : bool XPolygon::operator==( const XPolygon& rXPoly ) const
477 : {
478 0 : pImpXPolygon->CheckPointDelete();
479 0 : if (rXPoly.pImpXPolygon==pImpXPolygon) return true;
480 0 : return *rXPoly.pImpXPolygon == *pImpXPolygon;
481 : }
482 :
483 0 : bool XPolygon::operator!=( const XPolygon& rXPoly ) const
484 : {
485 0 : pImpXPolygon->CheckPointDelete();
486 0 : if (rXPoly.pImpXPolygon==pImpXPolygon) return false;
487 0 : return *rXPoly.pImpXPolygon != *pImpXPolygon;
488 : }
489 :
490 : /// get the flags for the point at the given position
491 1467 : XPolyFlags XPolygon::GetFlags( sal_uInt16 nPos ) const
492 : {
493 1467 : pImpXPolygon->CheckPointDelete();
494 1467 : return (XPolyFlags) pImpXPolygon->pFlagAry[nPos];
495 : }
496 :
497 : /// set the flags for the point at the given position
498 100 : void XPolygon::SetFlags( sal_uInt16 nPos, XPolyFlags eFlags )
499 : {
500 100 : pImpXPolygon->CheckPointDelete();
501 100 : CheckReference();
502 100 : pImpXPolygon->pFlagAry[nPos] = (sal_uInt8) eFlags;
503 100 : }
504 :
505 : /// short path to read the CONTROL flag directly (TODO: better explain what the sense behind this flag is!)
506 0 : bool XPolygon::IsControl(sal_uInt16 nPos) const
507 : {
508 0 : return ( (XPolyFlags) pImpXPolygon->pFlagAry[nPos] == XPOLY_CONTROL );
509 : }
510 :
511 : /// short path to read the SMOOTH and SYMMTR flag directly (TODO: better explain what the sense behind these flags is!)
512 0 : bool XPolygon::IsSmooth(sal_uInt16 nPos) const
513 : {
514 0 : XPolyFlags eFlag = (XPolyFlags) pImpXPolygon->pFlagAry[nPos];
515 0 : return ( eFlag == XPOLY_SMOOTH || eFlag == XPOLY_SYMMTR );
516 : }
517 :
518 : /** calculate the euclidean distance between two points
519 : *
520 : * @param nP1 The first point
521 : * @param nP2 The second point
522 : */
523 0 : double XPolygon::CalcDistance(sal_uInt16 nP1, sal_uInt16 nP2)
524 : {
525 0 : const Point& rP1 = pImpXPolygon->pPointAry[nP1];
526 0 : const Point& rP2 = pImpXPolygon->pPointAry[nP2];
527 0 : double fDx = rP2.X() - rP1.X();
528 0 : double fDy = rP2.Y() - rP1.Y();
529 0 : return sqrt(fDx * fDx + fDy * fDy);
530 : }
531 :
532 0 : void XPolygon::SubdivideBezier(sal_uInt16 nPos, bool bCalcFirst, double fT)
533 : {
534 0 : Point* pPoints = pImpXPolygon->pPointAry;
535 0 : double fT2 = fT * fT;
536 0 : double fT3 = fT * fT2;
537 0 : double fU = 1.0 - fT;
538 0 : double fU2 = fU * fU;
539 0 : double fU3 = fU * fU2;
540 0 : sal_uInt16 nIdx = nPos;
541 : short nPosInc, nIdxInc;
542 :
543 0 : if ( bCalcFirst )
544 : {
545 0 : nPos += 3;
546 0 : nPosInc = -1;
547 0 : nIdxInc = 0;
548 : }
549 : else
550 : {
551 0 : nPosInc = 1;
552 0 : nIdxInc = 1;
553 : }
554 0 : pPoints[nPos].X() = (long) (fU3 * pPoints[nIdx ].X() +
555 0 : fT * fU2 * pPoints[nIdx+1].X() * 3 +
556 0 : fT2 * fU * pPoints[nIdx+2].X() * 3 +
557 0 : fT3 * pPoints[nIdx+3].X());
558 0 : pPoints[nPos].Y() = (long) (fU3 * pPoints[nIdx ].Y() +
559 0 : fT * fU2 * pPoints[nIdx+1].Y() * 3 +
560 0 : fT2 * fU * pPoints[nIdx+2].Y() * 3 +
561 0 : fT3 * pPoints[nIdx+3].Y());
562 0 : nPos = nPos + nPosInc;
563 0 : nIdx = nIdx + nIdxInc;
564 0 : pPoints[nPos].X() = (long) (fU2 * pPoints[nIdx ].X() +
565 0 : fT * fU * pPoints[nIdx+1].X() * 2 +
566 0 : fT2 * pPoints[nIdx+2].X());
567 0 : pPoints[nPos].Y() = (long) (fU2 * pPoints[nIdx ].Y() +
568 0 : fT * fU * pPoints[nIdx+1].Y() * 2 +
569 0 : fT2 * pPoints[nIdx+2].Y());
570 0 : nPos = nPos + nPosInc;
571 0 : nIdx = nIdx + nIdxInc;
572 0 : pPoints[nPos].X() = (long) (fU * pPoints[nIdx ].X() +
573 0 : fT * pPoints[nIdx+1].X());
574 0 : pPoints[nPos].Y() = (long) (fU * pPoints[nIdx ].Y() +
575 0 : fT * pPoints[nIdx+1].Y());
576 0 : }
577 :
578 : /// Generate a Bézier arc
579 8 : void XPolygon::GenBezArc(const Point& rCenter, long nRx, long nRy,
580 : long nXHdl, long nYHdl, sal_uInt16 nStart, sal_uInt16 nEnd,
581 : sal_uInt16 nQuad, sal_uInt16 nFirst)
582 : {
583 8 : Point* pPoints = pImpXPolygon->pPointAry;
584 8 : pPoints[nFirst ] = rCenter;
585 8 : pPoints[nFirst+3] = rCenter;
586 :
587 8 : if ( nQuad == 1 || nQuad == 2 )
588 : {
589 4 : nRx = -nRx; nXHdl = -nXHdl;
590 : }
591 8 : if ( nQuad == 0 || nQuad == 1 )
592 : {
593 4 : nRy = -nRy; nYHdl = -nYHdl;
594 : }
595 :
596 8 : if ( nQuad == 0 || nQuad == 2 )
597 : {
598 4 : pPoints[nFirst].X() += nRx; pPoints[nFirst+3].Y() += nRy;
599 : }
600 : else
601 : {
602 4 : pPoints[nFirst].Y() += nRy; pPoints[nFirst+3].X() += nRx;
603 : }
604 8 : pPoints[nFirst+1] = pPoints[nFirst];
605 8 : pPoints[nFirst+2] = pPoints[nFirst+3];
606 :
607 8 : if ( nQuad == 0 || nQuad == 2 )
608 : {
609 4 : pPoints[nFirst+1].Y() += nYHdl; pPoints[nFirst+2].X() += nXHdl;
610 : }
611 : else
612 : {
613 4 : pPoints[nFirst+1].X() += nXHdl; pPoints[nFirst+2].Y() += nYHdl;
614 : }
615 8 : if ( nStart > 0 )
616 0 : SubdivideBezier(nFirst, false, (double)nStart / 900);
617 8 : if ( nEnd < 900 )
618 0 : SubdivideBezier(nFirst, true, (double)(nEnd-nStart) / (900-nStart));
619 8 : SetFlags(nFirst+1, XPOLY_CONTROL);
620 8 : SetFlags(nFirst+2, XPOLY_CONTROL);
621 8 : }
622 :
623 0 : bool XPolygon::CheckAngles(sal_uInt16& nStart, sal_uInt16 nEnd, sal_uInt16& nA1, sal_uInt16& nA2)
624 : {
625 0 : if ( nStart == 3600 ) nStart = 0;
626 0 : if ( nEnd == 0 ) nEnd = 3600;
627 0 : sal_uInt16 nStPrev = nStart;
628 0 : sal_uInt16 nMax = (nStart / 900 + 1) * 900;
629 0 : sal_uInt16 nMin = nMax - 900;
630 :
631 0 : if ( nEnd >= nMax || nEnd <= nStart ) nA2 = 900;
632 0 : else nA2 = nEnd - nMin;
633 0 : nA1 = nStart - nMin;
634 0 : nStart = nMax;
635 :
636 : // returns true when the last segment was calculated
637 0 : return (nStPrev < nEnd && nStart >= nEnd);
638 : }
639 :
640 : /** Calculate a smooth transition to connect two Bézier curves
641 : *
642 : * This is done by projecting the corresponding point onto a line between
643 : * two other points.
644 : *
645 : * @param nCenter The point at the end or beginning of the curve.
646 : * If nCenter is at the end of the polygon the point is moved
647 : * to the opposite side.
648 : * @param nDrag The moved point that specifies the relocation.
649 : * @param nPnt The point to modify.
650 : */
651 0 : void XPolygon::CalcSmoothJoin(sal_uInt16 nCenter, sal_uInt16 nDrag, sal_uInt16 nPnt)
652 : {
653 0 : CheckReference();
654 :
655 : // If nPoint is no control point, i.e. cannot be moved, than
656 : // move nDrag instead on the line between nCenter and nPnt
657 0 : if ( !IsControl(nPnt) )
658 : {
659 0 : sal_uInt16 nTmp = nDrag;
660 0 : nDrag = nPnt;
661 0 : nPnt = nTmp;
662 : }
663 0 : Point* pPoints = pImpXPolygon->pPointAry;
664 0 : Point aDiff = pPoints[nDrag] - pPoints[nCenter];
665 0 : double fDiv = CalcDistance(nCenter, nDrag);
666 :
667 0 : if ( fDiv )
668 : {
669 0 : double fRatio = CalcDistance(nCenter, nPnt) / fDiv;
670 : // keep the length if SMOOTH
671 0 : if ( GetFlags(nCenter) == XPOLY_SMOOTH || !IsControl(nDrag) )
672 : {
673 0 : aDiff.X() = (long) (fRatio * aDiff.X());
674 0 : aDiff.Y() = (long) (fRatio * aDiff.Y());
675 : }
676 0 : pPoints[nPnt] = pPoints[nCenter] - aDiff;
677 : }
678 0 : }
679 :
680 : /** Calculate tangent between two Bézier curves
681 : *
682 : * @param nCenter start or end point of the curves
683 : * @param nPrev previous reference point
684 : * @param nNext next reference point
685 : */
686 0 : void XPolygon::CalcTangent(sal_uInt16 nCenter, sal_uInt16 nPrev, sal_uInt16 nNext)
687 : {
688 0 : CheckReference();
689 :
690 0 : double fAbsLen = CalcDistance(nNext, nPrev);
691 :
692 0 : if ( fAbsLen )
693 : {
694 0 : const Point& rCenter = pImpXPolygon->pPointAry[nCenter];
695 0 : Point& rNext = pImpXPolygon->pPointAry[nNext];
696 0 : Point& rPrev = pImpXPolygon->pPointAry[nPrev];
697 0 : Point aDiff = rNext - rPrev;
698 0 : double fNextLen = CalcDistance(nCenter, nNext) / fAbsLen;
699 0 : double fPrevLen = CalcDistance(nCenter, nPrev) / fAbsLen;
700 :
701 : // same length for both sides if SYMMTR
702 0 : if ( GetFlags(nCenter) == XPOLY_SYMMTR )
703 : {
704 0 : fPrevLen = (fNextLen + fPrevLen) / 2;
705 0 : fNextLen = fPrevLen;
706 : }
707 0 : rNext.X() = rCenter.X() + (long) (fNextLen * aDiff.X());
708 0 : rNext.Y() = rCenter.Y() + (long) (fNextLen * aDiff.Y());
709 0 : rPrev.X() = rCenter.X() - (long) (fPrevLen * aDiff.X());
710 0 : rPrev.Y() = rCenter.Y() - (long) (fPrevLen * aDiff.Y());
711 : }
712 0 : }
713 :
714 : /// convert four polygon points into a Bézier curve
715 0 : void XPolygon::PointsToBezier(sal_uInt16 nFirst)
716 : {
717 : double nFullLength, nPart1Length, nPart2Length;
718 : double fX0, fY0, fX1, fY1, fX2, fY2, fX3, fY3;
719 : double fTx1, fTx2, fTy1, fTy2;
720 : double fT1, fU1, fT2, fU2, fV;
721 0 : Point* pPoints = pImpXPolygon->pPointAry;
722 :
723 0 : if ( nFirst > pImpXPolygon->nPoints - 4 || IsControl(nFirst) ||
724 0 : IsControl(nFirst+1) || IsControl(nFirst+2) || IsControl(nFirst+3) )
725 0 : return;
726 :
727 0 : CheckReference();
728 :
729 0 : fTx1 = pPoints[nFirst+1].X();
730 0 : fTy1 = pPoints[nFirst+1].Y();
731 0 : fTx2 = pPoints[nFirst+2].X();
732 0 : fTy2 = pPoints[nFirst+2].Y();
733 0 : fX0 = pPoints[nFirst ].X();
734 0 : fY0 = pPoints[nFirst ].Y();
735 0 : fX3 = pPoints[nFirst+3].X();
736 0 : fY3 = pPoints[nFirst+3].Y();
737 :
738 0 : nPart1Length = CalcDistance(nFirst, nFirst+1);
739 0 : nPart2Length = nPart1Length + CalcDistance(nFirst+1, nFirst+2);
740 0 : nFullLength = nPart2Length + CalcDistance(nFirst+2, nFirst+3);
741 0 : if ( nFullLength < 20 )
742 0 : return;
743 :
744 0 : if ( nPart2Length == nFullLength )
745 0 : nPart2Length -= 1;
746 0 : if ( nPart1Length == nFullLength )
747 0 : nPart1Length = nPart2Length - 1;
748 0 : if ( nPart1Length <= 0 )
749 0 : nPart1Length = 1;
750 0 : if ( nPart2Length <= 0 || nPart2Length == nPart1Length )
751 0 : nPart2Length = nPart1Length + 1;
752 :
753 0 : fT1 = nPart1Length / nFullLength;
754 0 : fU1 = 1.0 - fT1;
755 0 : fT2 = nPart2Length / nFullLength;
756 0 : fU2 = 1.0 - fT2;
757 0 : fV = 3 * (1.0 - (fT1 * fU2) / (fT2 * fU1));
758 :
759 0 : fX1 = fTx1 / (fT1 * fU1 * fU1) - fTx2 * fT1 / (fT2 * fT2 * fU1 * fU2);
760 0 : fX1 /= fV;
761 0 : fX1 -= fX0 * ( fU1 / fT1 + fU2 / fT2) / 3;
762 0 : fX1 += fX3 * ( fT1 * fT2 / (fU1 * fU2)) / 3;
763 :
764 0 : fY1 = fTy1 / (fT1 * fU1 * fU1) - fTy2 * fT1 / (fT2 * fT2 * fU1 * fU2);
765 0 : fY1 /= fV;
766 0 : fY1 -= fY0 * ( fU1 / fT1 + fU2 / fT2) / 3;
767 0 : fY1 += fY3 * ( fT1 * fT2 / (fU1 * fU2)) / 3;
768 :
769 0 : fX2 = fTx2 / (fT2 * fT2 * fU2 * 3) - fX0 * fU2 * fU2 / ( fT2 * fT2 * 3);
770 0 : fX2 -= fX1 * fU2 / fT2;
771 0 : fX2 -= fX3 * fT2 / (fU2 * 3);
772 :
773 0 : fY2 = fTy2 / (fT2 * fT2 * fU2 * 3) - fY0 * fU2 * fU2 / ( fT2 * fT2 * 3);
774 0 : fY2 -= fY1 * fU2 / fT2;
775 0 : fY2 -= fY3 * fT2 / (fU2 * 3);
776 :
777 0 : pPoints[nFirst+1] = Point((long) fX1, (long) fY1);
778 0 : pPoints[nFirst+2] = Point((long) fX2, (long) fY2);
779 0 : SetFlags(nFirst+1, XPOLY_CONTROL);
780 0 : SetFlags(nFirst+2, XPOLY_CONTROL);
781 : }
782 :
783 : /// scale in X- and/or Y-direction
784 0 : void XPolygon::Scale(double fSx, double fSy)
785 : {
786 0 : pImpXPolygon->CheckPointDelete();
787 0 : CheckReference();
788 :
789 0 : sal_uInt16 nPntCnt = pImpXPolygon->nPoints;
790 :
791 0 : for (sal_uInt16 i = 0; i < nPntCnt; i++)
792 : {
793 0 : Point& rPnt = pImpXPolygon->pPointAry[i];
794 0 : rPnt.X() = (long)(fSx * rPnt.X());
795 0 : rPnt.Y() = (long)(fSy * rPnt.Y());
796 : }
797 0 : }
798 :
799 : /**
800 : * Distort a polygon by scaling its coordinates relative to a reference
801 : * rectangle into an arbitrary rectangle.
802 : *
803 : * Mapping between polygon corners and reference rectangle:
804 : * 0: top left 0----1
805 : * 1: top right | |
806 : * 2: bottom right 3----2
807 : * 3: bottom left
808 : */
809 0 : void XPolygon::Distort(const Rectangle& rRefRect,
810 : const XPolygon& rDistortedRect)
811 : {
812 0 : pImpXPolygon->CheckPointDelete();
813 0 : CheckReference();
814 :
815 : long Xr, Wr;
816 : long Yr, Hr;
817 :
818 0 : Xr = rRefRect.Left();
819 0 : Yr = rRefRect.Top();
820 0 : Wr = rRefRect.GetWidth();
821 0 : Hr = rRefRect.GetHeight();
822 :
823 0 : if ( Wr && Hr )
824 : {
825 : long X1, X2, X3, X4;
826 : long Y1, Y2, Y3, Y4;
827 : DBG_ASSERT(rDistortedRect.pImpXPolygon->nPoints >= 4,
828 : "Distort: rectangle to small");
829 :
830 0 : X1 = rDistortedRect[0].X();
831 0 : Y1 = rDistortedRect[0].Y();
832 0 : X2 = rDistortedRect[1].X();
833 0 : Y2 = rDistortedRect[1].Y();
834 0 : X3 = rDistortedRect[3].X();
835 0 : Y3 = rDistortedRect[3].Y();
836 0 : X4 = rDistortedRect[2].X();
837 0 : Y4 = rDistortedRect[2].Y();
838 :
839 0 : sal_uInt16 nPntCnt = pImpXPolygon->nPoints;
840 :
841 0 : for (sal_uInt16 i = 0; i < nPntCnt; i++)
842 : {
843 : double fTx, fTy, fUx, fUy;
844 0 : Point& rPnt = pImpXPolygon->pPointAry[i];
845 :
846 0 : fTx = (double)(rPnt.X() - Xr) / Wr;
847 0 : fTy = (double)(rPnt.Y() - Yr) / Hr;
848 0 : fUx = 1.0 - fTx;
849 0 : fUy = 1.0 - fTy;
850 :
851 0 : rPnt.X() = (long) ( fUy * (fUx * X1 + fTx * X2) +
852 0 : fTy * (fUx * X3 + fTx * X4) );
853 0 : rPnt.Y() = (long) ( fUx * (fUy * Y1 + fTy * Y3) +
854 0 : fTx * (fUy * Y2 + fTy * Y4) );
855 : }
856 : }
857 0 : }
858 :
859 266 : basegfx::B2DPolygon XPolygon::getB2DPolygon() const
860 : {
861 : // #i74631# use tools Polygon class for conversion to not have the code doubled
862 : // here. This needs one more conversion but avoids different convertors in
863 : // the long run
864 : DBG_ASSERT(pImpXPolygon != 0, "XPolygon::getB2DPolygon(): XPolygon has no implementation incarnated (!)");
865 266 : const Polygon aSource(GetPointCount(), pImpXPolygon->pPointAry, pImpXPolygon->pFlagAry);
866 :
867 266 : return aSource.getB2DPolygon();
868 : }
869 :
870 301 : XPolygon::XPolygon(const basegfx::B2DPolygon& rPolygon)
871 : {
872 : // #i74631# use tools Polygon class for conversion to not have the code doubled
873 : // here. This needs one more conversion but avoids different convertors in
874 : // the long run
875 :
876 301 : const Polygon aSource(rPolygon);
877 301 : sal_uInt16 nSize = aSource.GetSize();
878 301 : pImpXPolygon = new ImpXPolygon( nSize );
879 301 : pImpXPolygon->nPoints = nSize;
880 :
881 3157 : for( sal_uInt16 i = 0; i < nSize; i++ )
882 : {
883 2856 : pImpXPolygon->pPointAry[i] = aSource[i];
884 2856 : pImpXPolygon->pFlagAry[i] = (sal_uInt8) aSource.GetFlags( i );
885 301 : }
886 301 : }
887 :
888 : // XPolyPolygon
889 :
890 0 : ImpXPolyPolygon::ImpXPolyPolygon( const ImpXPolyPolygon& rImpXPolyPoly ) :
891 0 : aXPolyList( rImpXPolyPoly.aXPolyList )
892 : {
893 0 : nRefCount = 1;
894 :
895 : // duplicate elements
896 0 : for ( size_t i = 0, n = aXPolyList.size(); i < n; ++i )
897 0 : aXPolyList[ i ] = new XPolygon( *aXPolyList[ i ] );
898 0 : }
899 :
900 378 : ImpXPolyPolygon::~ImpXPolyPolygon()
901 : {
902 425 : for ( size_t i = 0, n = aXPolyList.size(); i < n; ++i )
903 236 : delete aXPolyList[ i ];
904 189 : aXPolyList.clear();
905 189 : }
906 :
907 0 : bool ImpXPolyPolygon::operator==(const ImpXPolyPolygon& rImpXPolyPoly) const
908 : {
909 0 : size_t nCount = aXPolyList.size();
910 0 : const XPolygonList& rCmpList = rImpXPolyPoly.aXPolyList;
911 0 : if ( nCount != rCmpList.size() ) return false;
912 0 : bool bEq=true;
913 0 : for ( size_t i = nCount; i > 0 && bEq; )
914 : {
915 0 : i--;
916 0 : bEq = ( *aXPolyList[ i ] == *rCmpList[ i ] );
917 : }
918 0 : return bEq;
919 : }
920 :
921 18 : XPolyPolygon::XPolyPolygon( sal_uInt16 /*nInitSize*/, sal_uInt16 /*nResize*/ )
922 : {
923 18 : pImpXPolyPolygon = new ImpXPolyPolygon();
924 18 : }
925 :
926 0 : XPolyPolygon::XPolyPolygon( const XPolyPolygon& rXPolyPoly )
927 : {
928 0 : pImpXPolyPolygon = rXPolyPoly.pImpXPolyPolygon;
929 0 : pImpXPolyPolygon->nRefCount++;
930 0 : }
931 :
932 189 : XPolyPolygon::~XPolyPolygon()
933 : {
934 189 : if( pImpXPolyPolygon->nRefCount > 1 )
935 15 : pImpXPolyPolygon->nRefCount--;
936 : else
937 174 : delete pImpXPolyPolygon;
938 189 : }
939 :
940 : /// check reference counter and decouple if > 1
941 236 : void XPolyPolygon::CheckReference()
942 : {
943 236 : if( pImpXPolyPolygon->nRefCount > 1 )
944 : {
945 0 : pImpXPolyPolygon->nRefCount--;
946 0 : pImpXPolyPolygon = new ImpXPolyPolygon( *pImpXPolyPolygon );
947 : }
948 236 : }
949 :
950 236 : void XPolyPolygon::Insert( const XPolygon& rXPoly, sal_uInt16 nPos )
951 : {
952 236 : CheckReference();
953 236 : XPolygon* pXPoly = new XPolygon( rXPoly );
954 236 : if ( nPos < pImpXPolyPolygon->aXPolyList.size() )
955 : {
956 0 : XPolygonList::iterator it = pImpXPolyPolygon->aXPolyList.begin();
957 0 : ::std::advance( it, nPos );
958 0 : pImpXPolyPolygon->aXPolyList.insert( it, pXPoly );
959 : }
960 : else
961 236 : pImpXPolyPolygon->aXPolyList.push_back( pXPoly );
962 236 : }
963 :
964 : /// insert all XPolygons of a XPolyPolygon
965 0 : void XPolyPolygon::Insert( const XPolyPolygon& rXPolyPoly, sal_uInt16 nPos )
966 : {
967 0 : CheckReference();
968 :
969 0 : for ( size_t i = 0; i < rXPolyPoly.Count(); i++)
970 : {
971 0 : XPolygon* pXPoly = new XPolygon( rXPolyPoly[i] );
972 :
973 0 : if ( nPos < pImpXPolyPolygon->aXPolyList.size() )
974 : {
975 0 : XPolygonList::iterator it = pImpXPolyPolygon->aXPolyList.begin();
976 0 : ::std::advance( it, nPos );
977 0 : pImpXPolyPolygon->aXPolyList.insert( it, pXPoly );
978 0 : nPos++;
979 : }
980 : else
981 0 : pImpXPolyPolygon->aXPolyList.push_back( pXPoly );
982 : }
983 0 : }
984 :
985 0 : XPolygon XPolyPolygon::Remove( sal_uInt16 nPos )
986 : {
987 0 : CheckReference();
988 0 : XPolygonList::iterator it = pImpXPolyPolygon->aXPolyList.begin();
989 0 : ::std::advance( it, nPos );
990 0 : XPolygon* pTmpXPoly = *it;
991 0 : pImpXPolyPolygon->aXPolyList.erase( it );
992 0 : XPolygon aXPoly( *pTmpXPoly );
993 0 : delete pTmpXPoly;
994 0 : return aXPoly;
995 : }
996 :
997 173 : const XPolygon& XPolyPolygon::GetObject( sal_uInt16 nPos ) const
998 : {
999 173 : return *(pImpXPolyPolygon->aXPolyList[ nPos ]);
1000 : }
1001 :
1002 0 : void XPolyPolygon::Clear()
1003 : {
1004 0 : if ( pImpXPolyPolygon->nRefCount > 1 )
1005 : {
1006 0 : pImpXPolyPolygon->nRefCount--;
1007 0 : pImpXPolyPolygon = new ImpXPolyPolygon();
1008 : }
1009 : else
1010 : {
1011 0 : for( size_t i = 0, n = pImpXPolyPolygon->aXPolyList.size(); i < n; ++i )
1012 0 : delete pImpXPolyPolygon->aXPolyList[ i ];
1013 0 : pImpXPolyPolygon->aXPolyList.clear();
1014 : }
1015 0 : }
1016 :
1017 162 : sal_uInt16 XPolyPolygon::Count() const
1018 : {
1019 162 : return (sal_uInt16)(pImpXPolyPolygon->aXPolyList.size());
1020 : }
1021 :
1022 15 : Rectangle XPolyPolygon::GetBoundRect() const
1023 : {
1024 15 : size_t nXPoly = pImpXPolyPolygon->aXPolyList.size();
1025 15 : Rectangle aRect;
1026 :
1027 78 : for ( size_t n = 0; n < nXPoly; n++ )
1028 : {
1029 63 : const XPolygon* pXPoly = pImpXPolyPolygon->aXPolyList[ n ];
1030 63 : aRect.Union( pXPoly->GetBoundRect() );
1031 : }
1032 :
1033 15 : return aRect;
1034 : }
1035 :
1036 0 : XPolygon& XPolyPolygon::operator[]( sal_uInt16 nPos )
1037 : {
1038 0 : CheckReference();
1039 0 : return *( pImpXPolyPolygon->aXPolyList[ nPos ] );
1040 : }
1041 :
1042 15 : XPolyPolygon& XPolyPolygon::operator=( const XPolyPolygon& rXPolyPoly )
1043 : {
1044 15 : rXPolyPoly.pImpXPolyPolygon->nRefCount++;
1045 :
1046 15 : if( pImpXPolyPolygon->nRefCount > 1 )
1047 0 : pImpXPolyPolygon->nRefCount--;
1048 : else
1049 15 : delete pImpXPolyPolygon;
1050 :
1051 15 : pImpXPolyPolygon = rXPolyPoly.pImpXPolyPolygon;
1052 15 : return *this;
1053 : }
1054 :
1055 0 : bool XPolyPolygon::operator==( const XPolyPolygon& rXPolyPoly ) const
1056 : {
1057 0 : if (pImpXPolyPolygon==rXPolyPoly.pImpXPolyPolygon) return true;
1058 0 : return *pImpXPolyPolygon == *rXPolyPoly.pImpXPolyPolygon;
1059 : }
1060 :
1061 0 : bool XPolyPolygon::operator!=( const XPolyPolygon& rXPolyPoly ) const
1062 : {
1063 0 : if (pImpXPolyPolygon==rXPolyPoly.pImpXPolyPolygon) return false;
1064 0 : return *pImpXPolyPolygon != *rXPolyPoly.pImpXPolyPolygon;
1065 : }
1066 :
1067 : /**
1068 : * Distort a polygon by scaling its coordinates relative to a reference
1069 : * rectangle into an arbitrary rectangle.
1070 : *
1071 : * Mapping between polygon corners and reference rectangle:
1072 : * 0: top left 0----1
1073 : * 1: top right | |
1074 : * 2: bottom right 3----2
1075 : * 3: bottom left
1076 : */
1077 0 : void XPolyPolygon::Distort(const Rectangle& rRefRect,
1078 : const XPolygon& rDistortedRect)
1079 : {
1080 0 : CheckReference();
1081 :
1082 0 : for (size_t i = 0; i < Count(); i++)
1083 0 : pImpXPolyPolygon->aXPolyList[ i ]->Distort(rRefRect, rDistortedRect);
1084 0 : }
1085 :
1086 3 : basegfx::B2DPolyPolygon XPolyPolygon::getB2DPolyPolygon() const
1087 : {
1088 3 : basegfx::B2DPolyPolygon aRetval;
1089 :
1090 6 : for(sal_uInt16 a(0L); a < Count(); a++)
1091 : {
1092 3 : const XPolygon& rPoly = (*this)[a];
1093 3 : aRetval.append(rPoly.getB2DPolygon());
1094 : }
1095 :
1096 3 : return aRetval;
1097 : }
1098 :
1099 171 : XPolyPolygon::XPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon)
1100 : {
1101 171 : pImpXPolyPolygon = new ImpXPolyPolygon();
1102 :
1103 404 : for(sal_uInt32 a(0L); a < rPolyPolygon.count(); a++)
1104 : {
1105 233 : basegfx::B2DPolygon aCandidate = rPolyPolygon.getB2DPolygon(a);
1106 466 : XPolygon aNewPoly(aCandidate);
1107 233 : Insert(aNewPoly);
1108 233 : }
1109 171 : }
1110 :
1111 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|