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