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