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/diagnose.h>
21 : #include <basegfx/polygon/b2dpolygon.hxx>
22 : #include <basegfx/point/b2dpoint.hxx>
23 : #include <basegfx/vector/b2dvector.hxx>
24 : #include <basegfx/matrix/b2dhommatrix.hxx>
25 : #include <basegfx/curve/b2dcubicbezier.hxx>
26 : #include <rtl/instance.hxx>
27 : #include <basegfx/polygon/b2dpolygontools.hxx>
28 : #include <boost/scoped_ptr.hpp>
29 : #include <vector>
30 : #include <algorithm>
31 :
32 98650354 : struct CoordinateData2D : public basegfx::B2DPoint
33 : {
34 : public:
35 0 : CoordinateData2D() {}
36 :
37 17335035 : explicit CoordinateData2D(const basegfx::B2DPoint& rData)
38 17335035 : : B2DPoint(rData)
39 17335035 : {}
40 :
41 7714237 : CoordinateData2D& operator=(const basegfx::B2DPoint& rData)
42 : {
43 7714237 : B2DPoint::operator=(rData);
44 7714237 : return *this;
45 : }
46 :
47 6095477 : void transform(const basegfx::B2DHomMatrix& rMatrix)
48 : {
49 6095477 : *this *= rMatrix;
50 6095477 : }
51 : };
52 :
53 6027421 : class CoordinateDataArray2D
54 : {
55 : typedef ::std::vector< CoordinateData2D > CoordinateData2DVector;
56 :
57 : CoordinateData2DVector maVector;
58 :
59 : public:
60 141 : explicit CoordinateDataArray2D(sal_uInt32 nCount)
61 141 : : maVector(nCount)
62 : {
63 141 : }
64 :
65 6032676 : explicit CoordinateDataArray2D(const CoordinateDataArray2D& rOriginal)
66 6032676 : : maVector(rOriginal.maVector)
67 : {
68 6032676 : }
69 :
70 0 : CoordinateDataArray2D(const CoordinateDataArray2D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
71 0 : : maVector(rOriginal.maVector.begin() + nIndex, rOriginal.maVector.begin() + (nIndex + nCount))
72 : {
73 0 : }
74 :
75 18422269 : sal_uInt32 count() const
76 : {
77 18422269 : return maVector.size();
78 : }
79 :
80 60440 : bool operator==(const CoordinateDataArray2D& rCandidate) const
81 : {
82 60440 : return (maVector == rCandidate.maVector);
83 : }
84 :
85 134869333 : const basegfx::B2DPoint& getCoordinate(sal_uInt32 nIndex) const
86 : {
87 134869333 : return maVector[nIndex];
88 : }
89 :
90 7714237 : void setCoordinate(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue)
91 : {
92 7714237 : maVector[nIndex] = rValue;
93 7714237 : }
94 :
95 59019 : void reserve(sal_uInt32 nCount)
96 : {
97 59019 : maVector.reserve(nCount);
98 59019 : }
99 :
100 15291020 : void append(const CoordinateData2D& rValue)
101 : {
102 15291020 : maVector.push_back(rValue);
103 15291020 : }
104 :
105 2044015 : void insert(sal_uInt32 nIndex, const CoordinateData2D& rValue, sal_uInt32 nCount)
106 : {
107 2044015 : if(nCount)
108 : {
109 : // add nCount copies of rValue
110 2044015 : CoordinateData2DVector::iterator aIndex(maVector.begin());
111 2044015 : aIndex += nIndex;
112 2044015 : maVector.insert(aIndex, nCount, rValue);
113 : }
114 2044015 : }
115 :
116 2623 : void insert(sal_uInt32 nIndex, const CoordinateDataArray2D& rSource)
117 : {
118 2623 : const sal_uInt32 nCount(rSource.maVector.size());
119 :
120 2623 : if(nCount)
121 : {
122 : // insert data
123 2623 : CoordinateData2DVector::iterator aIndex(maVector.begin());
124 2623 : aIndex += nIndex;
125 2623 : CoordinateData2DVector::const_iterator aStart(rSource.maVector.begin());
126 2623 : CoordinateData2DVector::const_iterator aEnd(rSource.maVector.end());
127 2623 : maVector.insert(aIndex, aStart, aEnd);
128 : }
129 2623 : }
130 :
131 63868 : void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
132 : {
133 63868 : if(nCount)
134 : {
135 : // remove point data
136 63868 : CoordinateData2DVector::iterator aStart(maVector.begin());
137 63868 : aStart += nIndex;
138 63868 : const CoordinateData2DVector::iterator aEnd(aStart + nCount);
139 63868 : maVector.erase(aStart, aEnd);
140 : }
141 63868 : }
142 :
143 525 : void flip(bool bIsClosed)
144 : {
145 525 : if(maVector.size() > 1)
146 : {
147 : // to keep the same point at index 0, just flip all points except the
148 : // first one when closed
149 525 : const sal_uInt32 nHalfSize(bIsClosed ? (maVector.size() - 1) >> 1 : maVector.size() >> 1);
150 525 : CoordinateData2DVector::iterator aStart(bIsClosed ? maVector.begin() + 1 : maVector.begin());
151 525 : CoordinateData2DVector::iterator aEnd(maVector.end() - 1);
152 :
153 1397 : for(sal_uInt32 a(0); a < nHalfSize; a++)
154 : {
155 872 : ::std::swap(*aStart, *aEnd);
156 872 : ++aStart;
157 872 : --aEnd;
158 : }
159 : }
160 525 : }
161 :
162 665 : void removeDoublePointsAtBeginEnd()
163 : {
164 : // remove from end as long as there are at least two points
165 : // and begin/end are equal
166 1912 : while((maVector.size() > 1) && (maVector[0] == maVector[maVector.size() - 1]))
167 : {
168 582 : maVector.pop_back();
169 : }
170 665 : }
171 :
172 1090 : void removeDoublePointsWholeTrack()
173 : {
174 1090 : sal_uInt32 nIndex(0);
175 :
176 : // test as long as there are at least two points and as long as the index
177 : // is smaller or equal second last point
178 18525 : while((maVector.size() > 1) && (nIndex <= maVector.size() - 2))
179 : {
180 16345 : if(maVector[nIndex] == maVector[nIndex + 1])
181 : {
182 : // if next is same as index, delete next
183 1882 : maVector.erase(maVector.begin() + (nIndex + 1));
184 : }
185 : else
186 : {
187 : // if different, step forward
188 14463 : nIndex++;
189 : }
190 : }
191 1090 : }
192 :
193 1136733 : void transform(const basegfx::B2DHomMatrix& rMatrix)
194 : {
195 1136733 : CoordinateData2DVector::iterator aStart(maVector.begin());
196 1136733 : CoordinateData2DVector::iterator aEnd(maVector.end());
197 :
198 7232210 : for(; aStart != aEnd; ++aStart)
199 : {
200 6095477 : aStart->transform(rMatrix);
201 : }
202 1136733 : }
203 : };
204 :
205 1814770 : class ControlVectorPair2D
206 : {
207 : basegfx::B2DVector maPrevVector;
208 : basegfx::B2DVector maNextVector;
209 :
210 : public:
211 193977 : explicit ControlVectorPair2D() {}
212 :
213 2608103 : const basegfx::B2DVector& getPrevVector() const
214 : {
215 2608103 : return maPrevVector;
216 : }
217 :
218 423216 : void setPrevVector(const basegfx::B2DVector& rValue)
219 : {
220 423216 : if(rValue != maPrevVector)
221 371205 : maPrevVector = rValue;
222 423216 : }
223 :
224 2553400 : const basegfx::B2DVector& getNextVector() const
225 : {
226 2553400 : return maNextVector;
227 : }
228 :
229 415860 : void setNextVector(const basegfx::B2DVector& rValue)
230 : {
231 415860 : if(rValue != maNextVector)
232 363770 : maNextVector = rValue;
233 415860 : }
234 :
235 5357 : bool operator==(const ControlVectorPair2D& rData) const
236 : {
237 5357 : return (maPrevVector == rData.getPrevVector() && maNextVector == rData.getNextVector());
238 : }
239 :
240 317 : void flip()
241 : {
242 317 : ::std::swap(maPrevVector, maNextVector);
243 317 : }
244 : };
245 :
246 102742 : class ControlVectorArray2D
247 : {
248 : typedef ::std::vector< ControlVectorPair2D > ControlVectorPair2DVector;
249 :
250 : ControlVectorPair2DVector maVector;
251 : sal_uInt32 mnUsedVectors;
252 :
253 : public:
254 21628 : explicit ControlVectorArray2D(sal_uInt32 nCount)
255 : : maVector(nCount),
256 21628 : mnUsedVectors(0)
257 21628 : {}
258 :
259 0 : ControlVectorArray2D(const ControlVectorArray2D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
260 : : maVector(),
261 0 : mnUsedVectors(0)
262 : {
263 0 : ControlVectorPair2DVector::const_iterator aStart(rOriginal.maVector.begin());
264 0 : aStart += nIndex;
265 0 : ControlVectorPair2DVector::const_iterator aEnd(aStart);
266 0 : aEnd += nCount;
267 0 : maVector.reserve(nCount);
268 :
269 0 : for(; aStart != aEnd; ++aStart)
270 : {
271 0 : if(!aStart->getPrevVector().equalZero())
272 0 : mnUsedVectors++;
273 :
274 0 : if(!aStart->getNextVector().equalZero())
275 0 : mnUsedVectors++;
276 :
277 0 : maVector.push_back(*aStart);
278 : }
279 0 : }
280 :
281 1394 : bool operator==(const ControlVectorArray2D& rCandidate) const
282 : {
283 1394 : return (maVector == rCandidate.maVector);
284 : }
285 :
286 3093352 : bool isUsed() const
287 : {
288 3093352 : return (0 != mnUsedVectors);
289 : }
290 :
291 2001747 : const basegfx::B2DVector& getPrevVector(sal_uInt32 nIndex) const
292 : {
293 2001747 : return maVector[nIndex].getPrevVector();
294 : }
295 :
296 425161 : void setPrevVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
297 : {
298 425161 : bool bWasUsed(mnUsedVectors && !maVector[nIndex].getPrevVector().equalZero());
299 425161 : bool bIsUsed(!rValue.equalZero());
300 :
301 425161 : if(bWasUsed)
302 : {
303 311163 : if(bIsUsed)
304 : {
305 311153 : maVector[nIndex].setPrevVector(rValue);
306 : }
307 : else
308 : {
309 10 : maVector[nIndex].setPrevVector(basegfx::B2DVector::getEmptyVector());
310 10 : mnUsedVectors--;
311 : }
312 : }
313 : else
314 : {
315 113998 : if(bIsUsed)
316 : {
317 112053 : maVector[nIndex].setPrevVector(rValue);
318 112053 : mnUsedVectors++;
319 : }
320 : }
321 425161 : }
322 :
323 1974001 : const basegfx::B2DVector& getNextVector(sal_uInt32 nIndex) const
324 : {
325 1974001 : return maVector[nIndex].getNextVector();
326 : }
327 :
328 417343 : void setNextVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
329 : {
330 417343 : bool bWasUsed(mnUsedVectors && !maVector[nIndex].getNextVector().equalZero());
331 417343 : bool bIsUsed(!rValue.equalZero());
332 :
333 417343 : if(bWasUsed)
334 : {
335 311000 : if(bIsUsed)
336 : {
337 311000 : maVector[nIndex].setNextVector(rValue);
338 : }
339 : else
340 : {
341 0 : maVector[nIndex].setNextVector(basegfx::B2DVector::getEmptyVector());
342 0 : mnUsedVectors--;
343 : }
344 : }
345 : else
346 : {
347 106343 : if(bIsUsed)
348 : {
349 104860 : maVector[nIndex].setNextVector(rValue);
350 104860 : mnUsedVectors++;
351 : }
352 : }
353 417343 : }
354 :
355 57293 : void append(const ControlVectorPair2D& rValue)
356 : {
357 57293 : maVector.push_back(rValue);
358 :
359 57293 : if(!rValue.getPrevVector().equalZero())
360 0 : mnUsedVectors += 1;
361 :
362 57293 : if(!rValue.getNextVector().equalZero())
363 0 : mnUsedVectors += 1;
364 57293 : }
365 :
366 104562 : void insert(sal_uInt32 nIndex, const ControlVectorPair2D& rValue, sal_uInt32 nCount)
367 : {
368 104562 : if(nCount)
369 : {
370 : // add nCount copies of rValue
371 104562 : ControlVectorPair2DVector::iterator aIndex(maVector.begin());
372 104562 : aIndex += nIndex;
373 104562 : maVector.insert(aIndex, nCount, rValue);
374 :
375 104562 : if(!rValue.getPrevVector().equalZero())
376 0 : mnUsedVectors += nCount;
377 :
378 104562 : if(!rValue.getNextVector().equalZero())
379 0 : mnUsedVectors += nCount;
380 : }
381 104562 : }
382 :
383 177 : void insert(sal_uInt32 nIndex, const ControlVectorArray2D& rSource)
384 : {
385 177 : const sal_uInt32 nCount(rSource.maVector.size());
386 :
387 177 : if(nCount)
388 : {
389 : // insert data
390 177 : ControlVectorPair2DVector::iterator aIndex(maVector.begin());
391 177 : aIndex += nIndex;
392 177 : ControlVectorPair2DVector::const_iterator aStart(rSource.maVector.begin());
393 177 : ControlVectorPair2DVector::const_iterator aEnd(rSource.maVector.end());
394 177 : maVector.insert(aIndex, aStart, aEnd);
395 :
396 1172 : for(; aStart != aEnd; ++aStart)
397 : {
398 995 : if(!aStart->getPrevVector().equalZero())
399 800 : mnUsedVectors++;
400 :
401 995 : if(!aStart->getNextVector().equalZero())
402 800 : mnUsedVectors++;
403 : }
404 : }
405 177 : }
406 :
407 14175 : void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
408 : {
409 14175 : if(nCount)
410 : {
411 14175 : const ControlVectorPair2DVector::iterator aDeleteStart(maVector.begin() + nIndex);
412 14175 : const ControlVectorPair2DVector::iterator aDeleteEnd(aDeleteStart + nCount);
413 14175 : ControlVectorPair2DVector::const_iterator aStart(aDeleteStart);
414 :
415 28368 : for(; mnUsedVectors && aStart != aDeleteEnd; ++aStart)
416 : {
417 14193 : if(!aStart->getPrevVector().equalZero())
418 6836 : mnUsedVectors--;
419 :
420 14193 : if(mnUsedVectors && !aStart->getNextVector().equalZero())
421 2 : mnUsedVectors--;
422 : }
423 :
424 : // remove point data
425 14175 : maVector.erase(aDeleteStart, aDeleteEnd);
426 : }
427 14175 : }
428 :
429 54 : void flip(bool bIsClosed)
430 : {
431 54 : if(maVector.size() > 1)
432 : {
433 : // to keep the same point at index 0, just flip all points except the
434 : // first one when closed
435 54 : const sal_uInt32 nHalfSize(bIsClosed ? (maVector.size() - 1) >> 1 : maVector.size() >> 1);
436 54 : ControlVectorPair2DVector::iterator aStart(bIsClosed ? maVector.begin() + 1 : maVector.begin());
437 54 : ControlVectorPair2DVector::iterator aEnd(maVector.end() - 1);
438 :
439 198 : for(sal_uInt32 a(0); a < nHalfSize; a++)
440 : {
441 : // swap Prev and Next
442 144 : aStart->flip();
443 144 : aEnd->flip();
444 :
445 : // swap entries
446 144 : ::std::swap(*aStart, *aEnd);
447 :
448 144 : ++aStart;
449 144 : --aEnd;
450 : }
451 :
452 54 : if(aStart == aEnd)
453 : {
454 : // swap Prev and Next at middle element (if exists)
455 28 : aStart->flip();
456 : }
457 :
458 54 : if(bIsClosed)
459 : {
460 : // swap Prev and Next at start element
461 1 : maVector.begin()->flip();
462 : }
463 : }
464 54 : }
465 : };
466 :
467 4147525 : class ImplBufferedData
468 : {
469 : private:
470 : // Possibility to hold the last subdivision
471 : boost::scoped_ptr< basegfx::B2DPolygon > mpDefaultSubdivision;
472 :
473 : // Possibility to hold the last B2DRange calculation
474 : boost::scoped_ptr< basegfx::B2DRange > mpB2DRange;
475 :
476 : public:
477 4149735 : ImplBufferedData()
478 : : mpDefaultSubdivision(),
479 4149735 : mpB2DRange()
480 4149735 : {}
481 :
482 5369 : const basegfx::B2DPolygon& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon& rSource) const
483 : {
484 5369 : if(!mpDefaultSubdivision)
485 : {
486 2543 : const_cast< ImplBufferedData* >(this)->mpDefaultSubdivision.reset(new basegfx::B2DPolygon(basegfx::tools::adaptiveSubdivideByCount(rSource, 9)));
487 : }
488 :
489 5369 : return *mpDefaultSubdivision;
490 : }
491 :
492 5027456 : const basegfx::B2DRange& getB2DRange(const basegfx::B2DPolygon& rSource) const
493 : {
494 5027456 : if(!mpB2DRange)
495 : {
496 4149663 : basegfx::B2DRange aNewRange;
497 4149663 : const sal_uInt32 nPointCount(rSource.count());
498 :
499 4149663 : if(nPointCount)
500 : {
501 23626801 : for(sal_uInt32 a(0); a < nPointCount; a++)
502 : {
503 19477143 : aNewRange.expand(rSource.getB2DPoint(a));
504 : }
505 :
506 4149658 : if(rSource.areControlPointsUsed())
507 : {
508 27363 : const sal_uInt32 nEdgeCount(rSource.isClosed() ? nPointCount : nPointCount - 1);
509 :
510 27363 : if(nEdgeCount)
511 : {
512 27363 : basegfx::B2DCubicBezier aEdge;
513 27363 : aEdge.setStartPoint(rSource.getB2DPoint(0));
514 :
515 280838 : for(sal_uInt32 b(0); b < nEdgeCount; b++)
516 : {
517 253475 : const sal_uInt32 nNextIndex((b + 1) % nPointCount);
518 253475 : aEdge.setControlPointA(rSource.getNextControlPoint(b));
519 253475 : aEdge.setControlPointB(rSource.getPrevControlPoint(nNextIndex));
520 253475 : aEdge.setEndPoint(rSource.getB2DPoint(nNextIndex));
521 :
522 253475 : if(aEdge.isBezier())
523 : {
524 151546 : const basegfx::B2DRange aBezierRangeWithControlPoints(aEdge.getRange());
525 :
526 151546 : if(!aNewRange.isInside(aBezierRangeWithControlPoints))
527 : {
528 : // the range with control points of the current edge is not completely
529 : // inside the current range without control points. Expand current range by
530 : // subdividing the bezier segment.
531 : // Ideal here is a subdivision at the extreme values, so use
532 : // getAllExtremumPositions to get all extremas in one run
533 30484 : ::std::vector< double > aExtremas;
534 :
535 30484 : aExtremas.reserve(4);
536 30484 : aEdge.getAllExtremumPositions(aExtremas);
537 :
538 30484 : const sal_uInt32 nExtremaCount(aExtremas.size());
539 :
540 60434 : for(sal_uInt32 c(0); c < nExtremaCount; c++)
541 : {
542 29950 : aNewRange.expand(aEdge.interpolatePoint(aExtremas[c]));
543 30484 : }
544 : }
545 : }
546 :
547 : // prepare next edge
548 253475 : aEdge.setStartPoint(aEdge.getEndPoint());
549 27363 : }
550 : }
551 : }
552 : }
553 :
554 4149663 : const_cast< ImplBufferedData* >(this)->mpB2DRange.reset(new basegfx::B2DRange(aNewRange));
555 : }
556 :
557 5027456 : return *mpB2DRange;
558 : }
559 : };
560 :
561 6027421 : class ImplB2DPolygon
562 : {
563 : private:
564 : // The point vector. This vector exists always and defines the
565 : // count of members.
566 : CoordinateDataArray2D maPoints;
567 :
568 : // The control point vectors. This vectors are created on demand
569 : // and may be zero.
570 : boost::scoped_ptr< ControlVectorArray2D > mpControlVector;
571 :
572 : // buffered data for e.g. default subdivision and range
573 : boost::scoped_ptr< ImplBufferedData > mpBufferedData;
574 :
575 : // flag which decides if this polygon is opened or closed
576 : bool mbIsClosed;
577 :
578 : public:
579 5468 : const basegfx::B2DPolygon& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon& rSource) const
580 : {
581 5468 : if(!mpControlVector || !mpControlVector->isUsed())
582 : {
583 99 : return rSource;
584 : }
585 :
586 5369 : if(!mpBufferedData)
587 : {
588 544 : const_cast< ImplB2DPolygon* >(this)->mpBufferedData.reset(new ImplBufferedData);
589 : }
590 :
591 5369 : return mpBufferedData->getDefaultAdaptiveSubdivision(rSource);
592 : }
593 :
594 5027456 : const basegfx::B2DRange& getB2DRange(const basegfx::B2DPolygon& rSource) const
595 : {
596 5027456 : if(!mpBufferedData)
597 : {
598 4149191 : const_cast< ImplB2DPolygon* >(this)->mpBufferedData.reset(new ImplBufferedData);
599 : }
600 :
601 5027456 : return mpBufferedData->getB2DRange(rSource);
602 : }
603 :
604 141 : ImplB2DPolygon()
605 : : maPoints(0),
606 : mpControlVector(),
607 : mpBufferedData(),
608 141 : mbIsClosed(false)
609 141 : {}
610 :
611 6032676 : ImplB2DPolygon(const ImplB2DPolygon& rToBeCopied)
612 : : maPoints(rToBeCopied.maPoints),
613 : mpControlVector(),
614 : mpBufferedData(),
615 6032676 : mbIsClosed(rToBeCopied.mbIsClosed)
616 : {
617 : // complete initialization using copy
618 6032676 : if(rToBeCopied.mpControlVector && rToBeCopied.mpControlVector->isUsed())
619 : {
620 40587 : mpControlVector.reset( new ControlVectorArray2D(*rToBeCopied.mpControlVector) );
621 : }
622 6032676 : }
623 :
624 0 : ImplB2DPolygon(const ImplB2DPolygon& rToBeCopied, sal_uInt32 nIndex, sal_uInt32 nCount)
625 : : maPoints(rToBeCopied.maPoints, nIndex, nCount),
626 : mpControlVector(),
627 : mpBufferedData(),
628 0 : mbIsClosed(rToBeCopied.mbIsClosed)
629 : {
630 : // complete initialization using partly copy
631 0 : if(rToBeCopied.mpControlVector && rToBeCopied.mpControlVector->isUsed())
632 : {
633 0 : mpControlVector.reset( new ControlVectorArray2D(*rToBeCopied.mpControlVector, nIndex, nCount) );
634 :
635 0 : if(!mpControlVector->isUsed())
636 0 : mpControlVector.reset();
637 : }
638 0 : }
639 :
640 : ImplB2DPolygon& operator=( const ImplB2DPolygon& ) SAL_DELETED_FUNCTION;
641 :
642 17635825 : sal_uInt32 count() const
643 : {
644 17635825 : return maPoints.count();
645 : }
646 :
647 6626172 : bool isClosed() const
648 : {
649 6626172 : return mbIsClosed;
650 : }
651 :
652 4555255 : void setClosed(bool bNew)
653 : {
654 4555255 : if(bNew != mbIsClosed)
655 : {
656 4555255 : mpBufferedData.reset();
657 4555255 : mbIsClosed = bNew;
658 : }
659 4555255 : }
660 :
661 61742 : bool operator==(const ImplB2DPolygon& rCandidate) const
662 : {
663 61742 : if(mbIsClosed == rCandidate.mbIsClosed)
664 : {
665 60440 : if(maPoints == rCandidate.maPoints)
666 : {
667 43956 : bool bControlVectorsAreEqual(true);
668 :
669 43956 : if(mpControlVector)
670 : {
671 1394 : if(rCandidate.mpControlVector)
672 : {
673 1394 : bControlVectorsAreEqual = ((*mpControlVector) == (*rCandidate.mpControlVector));
674 : }
675 : else
676 : {
677 : // candidate has no control vector, so it's assumed all unused.
678 0 : bControlVectorsAreEqual = !mpControlVector->isUsed();
679 : }
680 : }
681 : else
682 : {
683 42562 : if(rCandidate.mpControlVector)
684 : {
685 : // we have no control vector, so it's assumed all unused.
686 28 : bControlVectorsAreEqual = !rCandidate.mpControlVector->isUsed();
687 : }
688 : }
689 :
690 43956 : if(bControlVectorsAreEqual)
691 : {
692 43928 : return true;
693 : }
694 : }
695 : }
696 :
697 17814 : return false;
698 : }
699 :
700 134234161 : const basegfx::B2DPoint& getPoint(sal_uInt32 nIndex) const
701 : {
702 134234161 : return maPoints.getCoordinate(nIndex);
703 : }
704 :
705 7267063 : void setPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue)
706 : {
707 7267063 : mpBufferedData.reset();
708 7267063 : maPoints.setCoordinate(nIndex, rValue);
709 7267063 : }
710 :
711 59019 : void reserve(sal_uInt32 nCount)
712 : {
713 59019 : maPoints.reserve(nCount);
714 59019 : }
715 :
716 15291020 : void append(const basegfx::B2DPoint& rPoint)
717 : {
718 15291020 : mpBufferedData.reset(); // TODO: is this needed?
719 15291020 : const CoordinateData2D aCoordinate(rPoint);
720 15291020 : maPoints.append(aCoordinate);
721 :
722 15291020 : if(mpControlVector)
723 : {
724 57293 : const ControlVectorPair2D aVectorPair;
725 57293 : mpControlVector->append(aVectorPair);
726 15291020 : }
727 15291020 : }
728 :
729 2044015 : void insert(sal_uInt32 nIndex, const basegfx::B2DPoint& rPoint, sal_uInt32 nCount)
730 : {
731 2044015 : if(nCount)
732 : {
733 2044015 : mpBufferedData.reset();
734 2044015 : CoordinateData2D aCoordinate(rPoint);
735 2044015 : maPoints.insert(nIndex, aCoordinate, nCount);
736 :
737 2044015 : if(mpControlVector)
738 : {
739 104558 : ControlVectorPair2D aVectorPair;
740 104558 : mpControlVector->insert(nIndex, aVectorPair, nCount);
741 2044015 : }
742 : }
743 2044015 : }
744 :
745 1540785 : const basegfx::B2DVector& getPrevControlVector(sal_uInt32 nIndex) const
746 : {
747 1540785 : if(mpControlVector)
748 : {
749 1540354 : return mpControlVector->getPrevVector(nIndex);
750 : }
751 : else
752 : {
753 431 : return basegfx::B2DVector::getEmptyVector();
754 : }
755 : }
756 :
757 114333 : void setPrevControlVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
758 : {
759 114333 : if(!mpControlVector)
760 : {
761 1206 : if(!rValue.equalZero())
762 : {
763 1205 : mpBufferedData.reset();
764 1205 : mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
765 1205 : mpControlVector->setPrevVector(nIndex, rValue);
766 : }
767 : }
768 : else
769 : {
770 113127 : mpBufferedData.reset();
771 113127 : mpControlVector->setPrevVector(nIndex, rValue);
772 :
773 113127 : if(!mpControlVector->isUsed())
774 0 : mpControlVector.reset();
775 : }
776 114333 : }
777 :
778 1519356 : const basegfx::B2DVector& getNextControlVector(sal_uInt32 nIndex) const
779 : {
780 1519356 : if(mpControlVector)
781 : {
782 1519194 : return mpControlVector->getNextVector(nIndex);
783 : }
784 : else
785 : {
786 162 : return basegfx::B2DVector::getEmptyVector();
787 : }
788 : }
789 :
790 109538 : void setNextControlVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
791 : {
792 109538 : if(!mpControlVector)
793 : {
794 21150 : if(!rValue.equalZero())
795 : {
796 20344 : mpBufferedData.reset();
797 20344 : mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
798 20344 : mpControlVector->setNextVector(nIndex, rValue);
799 : }
800 : }
801 : else
802 : {
803 88388 : mpBufferedData.reset();
804 88388 : mpControlVector->setNextVector(nIndex, rValue);
805 :
806 88388 : if(!mpControlVector->isUsed())
807 0 : mpControlVector.reset();
808 : }
809 109538 : }
810 :
811 13542205 : bool areControlPointsUsed() const
812 : {
813 13542205 : return (mpControlVector && mpControlVector->isUsed());
814 : }
815 :
816 1 : void resetControlVectors()
817 : {
818 1 : mpBufferedData.reset();
819 1 : mpControlVector.reset();
820 1 : }
821 :
822 1 : void setControlVectors(sal_uInt32 nIndex, const basegfx::B2DVector& rPrev, const basegfx::B2DVector& rNext)
823 : {
824 1 : setPrevControlVector(nIndex, rPrev);
825 1 : setNextControlVector(nIndex, rNext);
826 1 : }
827 :
828 104766 : void appendBezierSegment(const basegfx::B2DVector& rNext, const basegfx::B2DVector& rPrev, const basegfx::B2DPoint& rPoint)
829 : {
830 104766 : mpBufferedData.reset();
831 104766 : const sal_uInt32 nCount(maPoints.count());
832 :
833 104766 : if(nCount)
834 : {
835 104765 : setNextControlVector(nCount - 1, rNext);
836 : }
837 :
838 104766 : insert(nCount, rPoint, 1);
839 104766 : setPrevControlVector(nCount, rPrev);
840 104766 : }
841 :
842 2623 : void insert(sal_uInt32 nIndex, const ImplB2DPolygon& rSource)
843 : {
844 2623 : const sal_uInt32 nCount(rSource.maPoints.count());
845 :
846 2623 : if(nCount)
847 : {
848 2623 : mpBufferedData.reset();
849 :
850 2623 : if(rSource.mpControlVector && rSource.mpControlVector->isUsed() && !mpControlVector)
851 : {
852 79 : mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
853 : }
854 :
855 2623 : maPoints.insert(nIndex, rSource.maPoints);
856 :
857 2623 : if(rSource.mpControlVector)
858 : {
859 177 : mpControlVector->insert(nIndex, *rSource.mpControlVector);
860 :
861 177 : if(!mpControlVector->isUsed())
862 0 : mpControlVector.reset();
863 : }
864 2446 : else if(mpControlVector)
865 : {
866 4 : ControlVectorPair2D aVectorPair;
867 4 : mpControlVector->insert(nIndex, aVectorPair, nCount);
868 : }
869 : }
870 2623 : }
871 :
872 63868 : void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
873 : {
874 63868 : if(nCount)
875 : {
876 63868 : mpBufferedData.reset();
877 63868 : maPoints.remove(nIndex, nCount);
878 :
879 63868 : if(mpControlVector)
880 : {
881 14175 : mpControlVector->remove(nIndex, nCount);
882 :
883 14175 : if(!mpControlVector->isUsed())
884 0 : mpControlVector.reset();
885 : }
886 : }
887 63868 : }
888 :
889 525 : void flip()
890 : {
891 525 : if(maPoints.count() > 1)
892 : {
893 525 : mpBufferedData.reset();
894 :
895 : // flip points
896 525 : maPoints.flip(mbIsClosed);
897 :
898 525 : if(mpControlVector)
899 : {
900 : // flip control vector
901 54 : mpControlVector->flip(mbIsClosed);
902 : }
903 : }
904 525 : }
905 :
906 31581 : bool hasDoublePoints() const
907 : {
908 31581 : if(mbIsClosed)
909 : {
910 : // check for same start and end point
911 9998 : const sal_uInt32 nIndex(maPoints.count() - 1);
912 :
913 9998 : if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
914 : {
915 3174 : if(mpControlVector)
916 : {
917 2643 : if(mpControlVector->getNextVector(nIndex).equalZero() && mpControlVector->getPrevVector(0).equalZero())
918 : {
919 2643 : return true;
920 : }
921 : }
922 : else
923 : {
924 531 : return true;
925 : }
926 : }
927 : }
928 :
929 : // test for range
930 82051 : for(sal_uInt32 a(0); a < maPoints.count() - 1; a++)
931 : {
932 54815 : if(maPoints.getCoordinate(a) == maPoints.getCoordinate(a + 1))
933 : {
934 1177 : if(mpControlVector)
935 : {
936 454 : if(mpControlVector->getNextVector(a).equalZero() && mpControlVector->getPrevVector(a + 1).equalZero())
937 : {
938 448 : return true;
939 : }
940 : }
941 : else
942 : {
943 723 : return true;
944 : }
945 : }
946 : }
947 :
948 27236 : return false;
949 : }
950 :
951 3731 : void removeDoublePointsAtBeginEnd()
952 : {
953 : // Only remove DoublePoints at Begin and End when poly is closed
954 3731 : if(mbIsClosed)
955 : {
956 2912 : mpBufferedData.reset();
957 :
958 2912 : if(mpControlVector)
959 : {
960 : bool bRemove;
961 :
962 5255 : do
963 : {
964 5255 : bRemove = false;
965 :
966 5255 : if(maPoints.count() > 1)
967 : {
968 5255 : const sal_uInt32 nIndex(maPoints.count() - 1);
969 :
970 5255 : if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
971 : {
972 3010 : if(mpControlVector)
973 : {
974 3010 : if(mpControlVector->getNextVector(nIndex).equalZero() && mpControlVector->getPrevVector(0).equalZero())
975 : {
976 3008 : bRemove = true;
977 : }
978 : }
979 : else
980 : {
981 0 : bRemove = true;
982 : }
983 : }
984 : }
985 :
986 5255 : if(bRemove)
987 : {
988 3008 : const sal_uInt32 nIndex(maPoints.count() - 1);
989 :
990 3008 : if(mpControlVector && !mpControlVector->getPrevVector(nIndex).equalZero())
991 : {
992 1291 : mpControlVector->setPrevVector(0, mpControlVector->getPrevVector(nIndex));
993 : }
994 :
995 3008 : remove(nIndex, 1);
996 : }
997 : }
998 : while(bRemove);
999 : }
1000 : else
1001 : {
1002 665 : maPoints.removeDoublePointsAtBeginEnd();
1003 : }
1004 : }
1005 3731 : }
1006 :
1007 3731 : void removeDoublePointsWholeTrack()
1008 : {
1009 3731 : mpBufferedData.reset();
1010 :
1011 3731 : if(mpControlVector)
1012 : {
1013 2641 : sal_uInt32 nIndex(0);
1014 :
1015 : // test as long as there are at least two points and as long as the index
1016 : // is smaller or equal second last point
1017 29213 : while((maPoints.count() > 1) && (nIndex <= maPoints.count() - 2))
1018 : {
1019 23931 : bool bRemove(maPoints.getCoordinate(nIndex) == maPoints.getCoordinate(nIndex + 1));
1020 :
1021 23931 : if(bRemove)
1022 : {
1023 1526 : if(mpControlVector)
1024 : {
1025 1526 : if(!mpControlVector->getNextVector(nIndex).equalZero() || !mpControlVector->getPrevVector(nIndex + 1).equalZero())
1026 : {
1027 3 : bRemove = false;
1028 : }
1029 : }
1030 : }
1031 :
1032 23931 : if(bRemove)
1033 : {
1034 1523 : if(mpControlVector && !mpControlVector->getPrevVector(nIndex).equalZero())
1035 : {
1036 775 : mpControlVector->setPrevVector(nIndex + 1, mpControlVector->getPrevVector(nIndex));
1037 : }
1038 :
1039 : // if next is same as index and the control vectors are unused, delete index
1040 1523 : remove(nIndex, 1);
1041 : }
1042 : else
1043 : {
1044 : // if different, step forward
1045 22408 : nIndex++;
1046 : }
1047 : }
1048 : }
1049 : else
1050 : {
1051 1090 : maPoints.removeDoublePointsWholeTrack();
1052 : }
1053 3731 : }
1054 :
1055 1187750 : void transform(const basegfx::B2DHomMatrix& rMatrix)
1056 : {
1057 1187750 : mpBufferedData.reset();
1058 :
1059 1187750 : if(mpControlVector)
1060 : {
1061 498191 : for(sal_uInt32 a(0); a < maPoints.count(); a++)
1062 : {
1063 447174 : basegfx::B2DPoint aCandidate = maPoints.getCoordinate(a);
1064 :
1065 447174 : if(mpControlVector->isUsed())
1066 : {
1067 447174 : const basegfx::B2DVector& rPrevVector(mpControlVector->getPrevVector(a));
1068 447174 : const basegfx::B2DVector& rNextVector(mpControlVector->getNextVector(a));
1069 :
1070 447174 : if(!rPrevVector.equalZero())
1071 : {
1072 308763 : basegfx::B2DVector aPrevVector(rMatrix * rPrevVector);
1073 308763 : mpControlVector->setPrevVector(a, aPrevVector);
1074 : }
1075 :
1076 447174 : if(!rNextVector.equalZero())
1077 : {
1078 308611 : basegfx::B2DVector aNextVector(rMatrix * rNextVector);
1079 308611 : mpControlVector->setNextVector(a, aNextVector);
1080 : }
1081 : }
1082 :
1083 447174 : aCandidate *= rMatrix;
1084 447174 : maPoints.setCoordinate(a, aCandidate);
1085 447174 : }
1086 :
1087 51017 : if(!mpControlVector->isUsed())
1088 0 : mpControlVector.reset();
1089 : }
1090 : else
1091 : {
1092 1136733 : maPoints.transform(rMatrix);
1093 : }
1094 1187750 : }
1095 : };
1096 :
1097 : namespace basegfx
1098 : {
1099 : namespace
1100 : {
1101 : struct DefaultPolygon: public rtl::Static<B2DPolygon::ImplType, DefaultPolygon> {};
1102 : }
1103 :
1104 4907034 : B2DPolygon::B2DPolygon()
1105 4907034 : : mpPolygon(DefaultPolygon::get())
1106 4907034 : {}
1107 :
1108 19490185 : B2DPolygon::B2DPolygon(const B2DPolygon& rPolygon)
1109 19490185 : : mpPolygon(rPolygon.mpPolygon)
1110 19490185 : {}
1111 :
1112 0 : B2DPolygon::B2DPolygon(const B2DPolygon& rPolygon, sal_uInt32 nIndex, sal_uInt32 nCount)
1113 0 : : mpPolygon(ImplB2DPolygon(*rPolygon.mpPolygon, nIndex, nCount))
1114 : {
1115 : // TODO(P2): one extra temporary here (cow_wrapper copies
1116 : // given ImplB2DPolygon into its internal impl_t wrapper type)
1117 : OSL_ENSURE(nIndex + nCount <= rPolygon.mpPolygon->count(), "B2DPolygon constructor outside range (!)");
1118 0 : }
1119 :
1120 24390939 : B2DPolygon::~B2DPolygon()
1121 : {
1122 24390939 : }
1123 :
1124 97545 : B2DPolygon& B2DPolygon::operator=(const B2DPolygon& rPolygon)
1125 : {
1126 97545 : mpPolygon = rPolygon.mpPolygon;
1127 97545 : return *this;
1128 : }
1129 :
1130 138 : void B2DPolygon::makeUnique()
1131 : {
1132 138 : mpPolygon.make_unique();
1133 138 : }
1134 :
1135 64410 : bool B2DPolygon::operator==(const B2DPolygon& rPolygon) const
1136 : {
1137 64410 : if(mpPolygon.same_object(rPolygon.mpPolygon))
1138 2668 : return true;
1139 :
1140 61742 : return ((*mpPolygon) == (*rPolygon.mpPolygon));
1141 : }
1142 :
1143 7089 : bool B2DPolygon::operator!=(const B2DPolygon& rPolygon) const
1144 : {
1145 7089 : return !(*this == rPolygon);
1146 : }
1147 :
1148 13449111 : sal_uInt32 B2DPolygon::count() const
1149 : {
1150 13449111 : return mpPolygon->count();
1151 : }
1152 :
1153 123407839 : B2DPoint B2DPolygon::getB2DPoint(sal_uInt32 nIndex) const
1154 : {
1155 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1156 :
1157 123407839 : return mpPolygon->getPoint(nIndex);
1158 : }
1159 :
1160 7748922 : void B2DPolygon::setB2DPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1161 : {
1162 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1163 :
1164 7748922 : if(mpPolygon->getPoint(nIndex) != rValue)
1165 : {
1166 7267063 : mpPolygon->setPoint(nIndex, rValue);
1167 : }
1168 7748922 : }
1169 :
1170 59019 : void B2DPolygon::reserve(sal_uInt32 nCount)
1171 : {
1172 59019 : mpPolygon->reserve(nCount);
1173 59019 : }
1174 :
1175 260 : void B2DPolygon::insert(sal_uInt32 nIndex, const B2DPoint& rPoint, sal_uInt32 nCount)
1176 : {
1177 : OSL_ENSURE(nIndex <= mpPolygon->count(), "B2DPolygon Insert outside range (!)");
1178 :
1179 260 : if(nCount)
1180 : {
1181 260 : mpPolygon->insert(nIndex, rPoint, nCount);
1182 : }
1183 260 : }
1184 :
1185 1937261 : void B2DPolygon::append(const B2DPoint& rPoint, sal_uInt32 nCount)
1186 : {
1187 1937261 : if(nCount)
1188 : {
1189 1937261 : mpPolygon->insert(mpPolygon->count(), rPoint, nCount);
1190 : }
1191 1937261 : }
1192 :
1193 15291020 : void B2DPolygon::append(const B2DPoint& rPoint)
1194 : {
1195 15291020 : mpPolygon->append(rPoint);
1196 15291020 : }
1197 :
1198 693875 : B2DPoint B2DPolygon::getPrevControlPoint(sal_uInt32 nIndex) const
1199 : {
1200 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1201 :
1202 693875 : if(mpPolygon->areControlPointsUsed())
1203 : {
1204 657861 : return mpPolygon->getPoint(nIndex) + mpPolygon->getPrevControlVector(nIndex);
1205 : }
1206 : else
1207 : {
1208 36014 : return mpPolygon->getPoint(nIndex);
1209 : }
1210 : }
1211 :
1212 688225 : B2DPoint B2DPolygon::getNextControlPoint(sal_uInt32 nIndex) const
1213 : {
1214 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1215 :
1216 688225 : if(mpPolygon->areControlPointsUsed())
1217 : {
1218 652255 : return mpPolygon->getPoint(nIndex) + mpPolygon->getNextControlVector(nIndex);
1219 : }
1220 : else
1221 : {
1222 35970 : return mpPolygon->getPoint(nIndex);
1223 : }
1224 : }
1225 :
1226 12508 : void B2DPolygon::setPrevControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1227 : {
1228 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1229 12508 : const basegfx::B2DVector aNewVector(rValue - mpPolygon->getPoint(nIndex));
1230 :
1231 12508 : if(mpPolygon->getPrevControlVector(nIndex) != aNewVector)
1232 : {
1233 9556 : mpPolygon->setPrevControlVector(nIndex, aNewVector);
1234 12508 : }
1235 12508 : }
1236 :
1237 7688 : void B2DPolygon::setNextControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1238 : {
1239 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1240 7688 : const basegfx::B2DVector aNewVector(rValue - mpPolygon->getPoint(nIndex));
1241 :
1242 7688 : if(mpPolygon->getNextControlVector(nIndex) != aNewVector)
1243 : {
1244 4772 : mpPolygon->setNextControlVector(nIndex, aNewVector);
1245 7688 : }
1246 7688 : }
1247 :
1248 1 : void B2DPolygon::setControlPoints(sal_uInt32 nIndex, const basegfx::B2DPoint& rPrev, const basegfx::B2DPoint& rNext)
1249 : {
1250 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1251 1 : const B2DPoint aPoint(mpPolygon->getPoint(nIndex));
1252 2 : const basegfx::B2DVector aNewPrev(rPrev - aPoint);
1253 2 : const basegfx::B2DVector aNewNext(rNext - aPoint);
1254 :
1255 1 : if(mpPolygon->getPrevControlVector(nIndex) != aNewPrev || mpPolygon->getNextControlVector(nIndex) != aNewNext)
1256 : {
1257 1 : mpPolygon->setControlVectors(nIndex, aNewPrev, aNewNext);
1258 1 : }
1259 1 : }
1260 :
1261 10 : void B2DPolygon::resetPrevControlPoint(sal_uInt32 nIndex)
1262 : {
1263 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1264 :
1265 10 : if(mpPolygon->areControlPointsUsed() && !mpPolygon->getPrevControlVector(nIndex).equalZero())
1266 : {
1267 10 : mpPolygon->setPrevControlVector(nIndex, B2DVector::getEmptyVector());
1268 : }
1269 10 : }
1270 :
1271 0 : void B2DPolygon::resetNextControlPoint(sal_uInt32 nIndex)
1272 : {
1273 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1274 :
1275 0 : if(mpPolygon->areControlPointsUsed() && !mpPolygon->getNextControlVector(nIndex).equalZero())
1276 : {
1277 0 : mpPolygon->setNextControlVector(nIndex, B2DVector::getEmptyVector());
1278 : }
1279 0 : }
1280 :
1281 1 : void B2DPolygon::resetControlPoints()
1282 : {
1283 1 : if(mpPolygon->areControlPointsUsed())
1284 : {
1285 1 : mpPolygon->resetControlVectors();
1286 : }
1287 1 : }
1288 :
1289 106494 : void B2DPolygon::appendBezierSegment(
1290 : const B2DPoint& rNextControlPoint,
1291 : const B2DPoint& rPrevControlPoint,
1292 : const B2DPoint& rPoint)
1293 : {
1294 106494 : const B2DVector aNewNextVector(mpPolygon->count() ? B2DVector(rNextControlPoint - mpPolygon->getPoint(mpPolygon->count() - 1)) : B2DVector::getEmptyVector());
1295 212988 : const B2DVector aNewPrevVector(rPrevControlPoint - rPoint);
1296 :
1297 106494 : if(aNewNextVector.equalZero() && aNewPrevVector.equalZero())
1298 : {
1299 1728 : mpPolygon->insert(mpPolygon->count(), rPoint, 1);
1300 : }
1301 : else
1302 : {
1303 104766 : mpPolygon->appendBezierSegment(aNewNextVector, aNewPrevVector, rPoint);
1304 106494 : }
1305 106494 : }
1306 :
1307 11199014 : bool B2DPolygon::areControlPointsUsed() const
1308 : {
1309 11199014 : return mpPolygon->areControlPointsUsed();
1310 : }
1311 :
1312 16687 : bool B2DPolygon::isPrevControlPointUsed(sal_uInt32 nIndex) const
1313 : {
1314 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1315 :
1316 16687 : return (mpPolygon->areControlPointsUsed() && !mpPolygon->getPrevControlVector(nIndex).equalZero());
1317 : }
1318 :
1319 5683 : bool B2DPolygon::isNextControlPointUsed(sal_uInt32 nIndex) const
1320 : {
1321 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1322 :
1323 5683 : return (mpPolygon->areControlPointsUsed() && !mpPolygon->getNextControlVector(nIndex).equalZero());
1324 : }
1325 :
1326 155326 : B2VectorContinuity B2DPolygon::getContinuityInPoint(sal_uInt32 nIndex) const
1327 : {
1328 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1329 :
1330 155326 : if(mpPolygon->areControlPointsUsed())
1331 : {
1332 155326 : const B2DVector& rPrev(mpPolygon->getPrevControlVector(nIndex));
1333 155326 : const B2DVector& rNext(mpPolygon->getNextControlVector(nIndex));
1334 :
1335 155326 : return getContinuity(rPrev, rNext);
1336 : }
1337 : else
1338 : {
1339 0 : return B2VectorContinuity::NONE;
1340 : }
1341 : }
1342 :
1343 785226 : void B2DPolygon::getBezierSegment(sal_uInt32 nIndex, B2DCubicBezier& rTarget) const
1344 : {
1345 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1346 785226 : const bool bNextIndexValidWithoutClose(nIndex + 1 < mpPolygon->count());
1347 :
1348 785226 : if(bNextIndexValidWithoutClose || mpPolygon->isClosed())
1349 : {
1350 783384 : const sal_uInt32 nNextIndex(bNextIndexValidWithoutClose ? nIndex + 1 : 0);
1351 783384 : rTarget.setStartPoint(mpPolygon->getPoint(nIndex));
1352 783384 : rTarget.setEndPoint(mpPolygon->getPoint(nNextIndex));
1353 :
1354 783384 : if(mpPolygon->areControlPointsUsed())
1355 : {
1356 698430 : rTarget.setControlPointA(rTarget.getStartPoint() + mpPolygon->getNextControlVector(nIndex));
1357 698430 : rTarget.setControlPointB(rTarget.getEndPoint() + mpPolygon->getPrevControlVector(nNextIndex));
1358 : }
1359 : else
1360 : {
1361 : // no bezier, reset control poins at rTarget
1362 84954 : rTarget.setControlPointA(rTarget.getStartPoint());
1363 84954 : rTarget.setControlPointB(rTarget.getEndPoint());
1364 : }
1365 : }
1366 : else
1367 : {
1368 : // no valid edge at all, reset rTarget to current point
1369 1842 : const B2DPoint aPoint(mpPolygon->getPoint(nIndex));
1370 1842 : rTarget.setStartPoint(aPoint);
1371 1842 : rTarget.setEndPoint(aPoint);
1372 1842 : rTarget.setControlPointA(aPoint);
1373 1842 : rTarget.setControlPointB(aPoint);
1374 : }
1375 785226 : }
1376 :
1377 5468 : B2DPolygon B2DPolygon::getDefaultAdaptiveSubdivision() const
1378 : {
1379 5468 : return mpPolygon->getDefaultAdaptiveSubdivision(*this);
1380 : }
1381 :
1382 5027456 : B2DRange B2DPolygon::getB2DRange() const
1383 : {
1384 5027456 : return mpPolygon->getB2DRange(*this);
1385 : }
1386 :
1387 2645 : void B2DPolygon::append(const B2DPolygon& rPoly, sal_uInt32 nIndex, sal_uInt32 nCount)
1388 : {
1389 2645 : if(rPoly.count())
1390 : {
1391 2623 : if(!nCount)
1392 : {
1393 2623 : nCount = rPoly.count();
1394 : }
1395 :
1396 2623 : if(0 == nIndex && nCount == rPoly.count())
1397 : {
1398 2623 : mpPolygon->insert(mpPolygon->count(), *rPoly.mpPolygon);
1399 : }
1400 : else
1401 : {
1402 : OSL_ENSURE(nIndex + nCount <= rPoly.mpPolygon->count(), "B2DPolygon Append outside range (!)");
1403 0 : ImplB2DPolygon aTempPoly(*rPoly.mpPolygon, nIndex, nCount);
1404 0 : mpPolygon->insert(mpPolygon->count(), aTempPoly);
1405 : }
1406 : }
1407 2645 : }
1408 :
1409 59337 : void B2DPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
1410 : {
1411 : OSL_ENSURE(nIndex + nCount <= mpPolygon->count(), "B2DPolygon Remove outside range (!)");
1412 :
1413 59337 : if(nCount)
1414 : {
1415 59337 : mpPolygon->remove(nIndex, nCount);
1416 : }
1417 59337 : }
1418 :
1419 158335 : void B2DPolygon::clear()
1420 : {
1421 158335 : mpPolygon = DefaultPolygon::get();
1422 158335 : }
1423 :
1424 6558402 : bool B2DPolygon::isClosed() const
1425 : {
1426 6558402 : return mpPolygon->isClosed();
1427 : }
1428 :
1429 4715677 : void B2DPolygon::setClosed(bool bNew)
1430 : {
1431 4715677 : if(isClosed() != bNew)
1432 : {
1433 4555255 : mpPolygon->setClosed(bNew);
1434 : }
1435 4715677 : }
1436 :
1437 525 : void B2DPolygon::flip()
1438 : {
1439 525 : if(count() > 1)
1440 : {
1441 525 : mpPolygon->flip();
1442 : }
1443 525 : }
1444 :
1445 32049 : bool B2DPolygon::hasDoublePoints() const
1446 : {
1447 32049 : return (mpPolygon->count() > 1 && mpPolygon->hasDoublePoints());
1448 : }
1449 :
1450 25532 : void B2DPolygon::removeDoublePoints()
1451 : {
1452 25532 : if(hasDoublePoints())
1453 : {
1454 3731 : mpPolygon->removeDoublePointsAtBeginEnd();
1455 3731 : mpPolygon->removeDoublePointsWholeTrack();
1456 : }
1457 25532 : }
1458 :
1459 1214840 : void B2DPolygon::transform(const B2DHomMatrix& rMatrix)
1460 : {
1461 1214840 : if(mpPolygon->count() && !rMatrix.isIdentity())
1462 : {
1463 1187750 : mpPolygon->transform(rMatrix);
1464 : }
1465 1214840 : }
1466 :
1467 : } // end of namespace basegfx
1468 :
1469 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|