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 1270197 : struct CoordinateData2D : public basegfx::B2DPoint
35 : {
36 : public:
37 0 : CoordinateData2D() {}
38 :
39 216410 : explicit CoordinateData2D(const basegfx::B2DPoint& rData)
40 216410 : : B2DPoint(rData)
41 216410 : {}
42 :
43 160506 : CoordinateData2D& operator=(const basegfx::B2DPoint& rData)
44 : {
45 160506 : B2DPoint::operator=(rData);
46 160506 : return *this;
47 : }
48 :
49 9106 : void transform(const basegfx::B2DHomMatrix& rMatrix)
50 : {
51 9106 : *this *= rMatrix;
52 9106 : }
53 : };
54 :
55 : //////////////////////////////////////////////////////////////////////////////
56 :
57 94570 : class CoordinateDataArray2D
58 : {
59 : typedef ::std::vector< CoordinateData2D > CoordinateData2DVector;
60 :
61 : CoordinateData2DVector maVector;
62 :
63 : public:
64 26 : explicit CoordinateDataArray2D(sal_uInt32 nCount)
65 26 : : maVector(nCount)
66 : {
67 26 : }
68 :
69 94712 : explicit CoordinateDataArray2D(const CoordinateDataArray2D& rOriginal)
70 94712 : : maVector(rOriginal.maVector)
71 : {
72 94712 : }
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 288283 : sal_uInt32 count() const
80 : {
81 288283 : return maVector.size();
82 : }
83 :
84 712 : bool operator==(const CoordinateDataArray2D& rCandidate) const
85 : {
86 712 : return (maVector == rCandidate.maVector);
87 : }
88 :
89 1296832 : const basegfx::B2DPoint& getCoordinate(sal_uInt32 nIndex) const
90 : {
91 1296832 : return maVector[nIndex];
92 : }
93 :
94 160506 : void setCoordinate(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue)
95 : {
96 160506 : maVector[nIndex] = rValue;
97 160506 : }
98 :
99 15 : void reserve(sal_uInt32 nCount)
100 : {
101 15 : maVector.reserve(nCount);
102 15 : }
103 :
104 162568 : void append(const CoordinateData2D& rValue)
105 : {
106 162568 : maVector.push_back(rValue);
107 162568 : }
108 :
109 53842 : void insert(sal_uInt32 nIndex, const CoordinateData2D& rValue, sal_uInt32 nCount)
110 : {
111 53842 : if(nCount)
112 : {
113 : // add nCount copies of rValue
114 53842 : CoordinateData2DVector::iterator aIndex(maVector.begin());
115 53842 : aIndex += nIndex;
116 53842 : maVector.insert(aIndex, nCount, rValue);
117 : }
118 53842 : }
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 1222 : void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
136 : {
137 1222 : if(nCount)
138 : {
139 : // remove point data
140 1222 : CoordinateData2DVector::iterator aStart(maVector.begin());
141 1222 : aStart += nIndex;
142 1222 : const CoordinateData2DVector::iterator aEnd(aStart + nCount);
143 1222 : maVector.erase(aStart, aEnd);
144 : }
145 1222 : }
146 :
147 587 : void flip(bool bIsClosed)
148 : {
149 587 : 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 587 : const sal_uInt32 nHalfSize(bIsClosed ? (maVector.size() - 1) >> 1 : maVector.size() >> 1);
154 587 : CoordinateData2DVector::iterator aStart(bIsClosed ? maVector.begin() + 1 : maVector.begin());
155 587 : CoordinateData2DVector::iterator aEnd(maVector.end() - 1);
156 :
157 1558 : for(sal_uInt32 a(0); a < nHalfSize; a++)
158 : {
159 971 : ::std::swap(*aStart, *aEnd);
160 971 : ++aStart;
161 971 : --aEnd;
162 : }
163 : }
164 587 : }
165 :
166 17 : void removeDoublePointsAtBeginEnd()
167 : {
168 : // remove from end as long as there are at least two points
169 : // and begin/end are equal
170 37 : while((maVector.size() > 1) && (maVector[0] == maVector[maVector.size() - 1]))
171 : {
172 3 : maVector.pop_back();
173 : }
174 17 : }
175 :
176 17 : void removeDoublePointsWholeTrack()
177 : {
178 17 : 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 107 : while((maVector.size() > 1) && (nIndex <= maVector.size() - 2))
183 : {
184 73 : if(maVector[nIndex] == maVector[nIndex + 1])
185 : {
186 : // if next is same as index, delete next
187 14 : maVector.erase(maVector.begin() + (nIndex + 1));
188 : }
189 : else
190 : {
191 : // if different, step forward
192 59 : nIndex++;
193 : }
194 : }
195 17 : }
196 :
197 2975 : void transform(const basegfx::B2DHomMatrix& rMatrix)
198 : {
199 2975 : CoordinateData2DVector::iterator aStart(maVector.begin());
200 2975 : CoordinateData2DVector::iterator aEnd(maVector.end());
201 :
202 12081 : for(; aStart != aEnd; ++aStart)
203 : {
204 9106 : aStart->transform(rMatrix);
205 : }
206 2975 : }
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 22609 : class ControlVectorPair2D
244 : {
245 : basegfx::B2DVector maPrevVector;
246 : basegfx::B2DVector maNextVector;
247 :
248 : public:
249 3432 : explicit ControlVectorPair2D() {}
250 :
251 18540 : const basegfx::B2DVector& getPrevVector() const
252 : {
253 18540 : return maPrevVector;
254 : }
255 :
256 4582 : void setPrevVector(const basegfx::B2DVector& rValue)
257 : {
258 4582 : if(rValue != maPrevVector)
259 4341 : maPrevVector = rValue;
260 4582 : }
261 :
262 17964 : const basegfx::B2DVector& getNextVector() const
263 : {
264 17964 : return maNextVector;
265 : }
266 :
267 4606 : void setNextVector(const basegfx::B2DVector& rValue)
268 : {
269 4606 : if(rValue != maNextVector)
270 4358 : maNextVector = rValue;
271 4606 : }
272 :
273 117 : bool operator==(const ControlVectorPair2D& rData) const
274 : {
275 117 : 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 337 : class ControlVectorArray2D
287 : {
288 : typedef ::std::vector< ControlVectorPair2D > ControlVectorPair2DVector;
289 :
290 : ControlVectorPair2DVector maVector;
291 : sal_uInt32 mnUsedVectors;
292 :
293 : public:
294 229 : explicit ControlVectorArray2D(sal_uInt32 nCount)
295 : : maVector(nCount),
296 229 : mnUsedVectors(0)
297 229 : {}
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 9 : bool operator==(const ControlVectorArray2D& rCandidate) const
327 : {
328 9 : return (maVector == rCandidate.maVector);
329 : }
330 :
331 20146 : bool isUsed() const
332 : {
333 20146 : return (0 != mnUsedVectors);
334 : }
335 :
336 10585 : const basegfx::B2DVector& getPrevVector(sal_uInt32 nIndex) const
337 : {
338 10585 : return maVector[nIndex].getPrevVector();
339 : }
340 :
341 4642 : void setPrevVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
342 : {
343 4642 : bool bWasUsed(mnUsedVectors && !maVector[nIndex].getPrevVector().equalZero());
344 4642 : bool bIsUsed(!rValue.equalZero());
345 :
346 4642 : if(bWasUsed)
347 : {
348 2345 : if(bIsUsed)
349 : {
350 2345 : 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 2297 : if(bIsUsed)
361 : {
362 2237 : maVector[nIndex].setPrevVector(rValue);
363 2237 : mnUsedVectors++;
364 : }
365 : }
366 4642 : }
367 :
368 10264 : const basegfx::B2DVector& getNextVector(sal_uInt32 nIndex) const
369 : {
370 10264 : return maVector[nIndex].getNextVector();
371 : }
372 :
373 4614 : void setNextVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
374 : {
375 4614 : bool bWasUsed(mnUsedVectors && !maVector[nIndex].getNextVector().equalZero());
376 4614 : bool bIsUsed(!rValue.equalZero());
377 :
378 4614 : if(bWasUsed)
379 : {
380 2401 : if(bIsUsed)
381 : {
382 2401 : 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 2213 : if(bIsUsed)
393 : {
394 2205 : maVector[nIndex].setNextVector(rValue);
395 2205 : mnUsedVectors++;
396 : }
397 : }
398 4614 : }
399 :
400 753 : void append(const ControlVectorPair2D& rValue)
401 : {
402 753 : maVector.push_back(rValue);
403 :
404 753 : if(!rValue.getPrevVector().equalZero())
405 0 : mnUsedVectors += 1;
406 :
407 753 : if(!rValue.getNextVector().equalZero())
408 0 : mnUsedVectors += 1;
409 753 : }
410 :
411 2213 : void insert(sal_uInt32 nIndex, const ControlVectorPair2D& rValue, sal_uInt32 nCount)
412 : {
413 2213 : if(nCount)
414 : {
415 : // add nCount copies of rValue
416 2213 : ControlVectorPair2DVector::iterator aIndex(maVector.begin());
417 2213 : aIndex += nIndex;
418 2213 : maVector.insert(aIndex, nCount, rValue);
419 :
420 2213 : if(!rValue.getPrevVector().equalZero())
421 0 : mnUsedVectors += nCount;
422 :
423 2213 : if(!rValue.getNextVector().equalZero())
424 0 : mnUsedVectors += nCount;
425 : }
426 2213 : }
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 213 : void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
453 : {
454 213 : if(nCount)
455 : {
456 213 : const ControlVectorPair2DVector::iterator aDeleteStart(maVector.begin() + nIndex);
457 213 : const ControlVectorPair2DVector::iterator aDeleteEnd(aDeleteStart + nCount);
458 213 : ControlVectorPair2DVector::const_iterator aStart(aDeleteStart);
459 :
460 444 : for(; mnUsedVectors && aStart != aDeleteEnd; ++aStart)
461 : {
462 231 : if(!aStart->getPrevVector().equalZero())
463 85 : mnUsedVectors--;
464 :
465 231 : if(mnUsedVectors && !aStart->getNextVector().equalZero())
466 0 : mnUsedVectors--;
467 : }
468 :
469 : // remove point data
470 213 : maVector.erase(aDeleteStart, aDeleteEnd);
471 : }
472 213 : }
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 82916 : 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 82965 : ImplBufferedData()
525 : : mpDefaultSubdivision(),
526 82965 : mpB2DRange()
527 82965 : {}
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 83226 : const basegfx::B2DRange& getB2DRange(const basegfx::B2DPolygon& rSource) const
540 : {
541 83226 : if(!mpB2DRange)
542 : {
543 82965 : basegfx::B2DRange aNewRange;
544 82965 : const sal_uInt32 nPointCount(rSource.count());
545 :
546 82965 : if(nPointCount)
547 : {
548 419447 : for(sal_uInt32 a(0); a < nPointCount; a++)
549 : {
550 336482 : aNewRange.expand(rSource.getB2DPoint(a));
551 : }
552 :
553 82965 : if(rSource.areControlPointsUsed())
554 : {
555 35 : const sal_uInt32 nEdgeCount(rSource.isClosed() ? nPointCount : nPointCount - 1);
556 :
557 35 : if(nEdgeCount)
558 : {
559 35 : basegfx::B2DCubicBezier aEdge;
560 35 : aEdge.setStartPoint(rSource.getB2DPoint(0));
561 :
562 470 : for(sal_uInt32 b(0); b < nEdgeCount; b++)
563 : {
564 435 : const sal_uInt32 nNextIndex((b + 1) % nPointCount);
565 435 : aEdge.setControlPointA(rSource.getNextControlPoint(b));
566 435 : aEdge.setControlPointB(rSource.getPrevControlPoint(nNextIndex));
567 435 : aEdge.setEndPoint(rSource.getB2DPoint(nNextIndex));
568 :
569 435 : if(aEdge.isBezier())
570 : {
571 391 : const basegfx::B2DRange aBezierRangeWithControlPoints(aEdge.getRange());
572 :
573 391 : 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 102 : ::std::vector< double > aExtremas;
581 :
582 102 : aExtremas.reserve(4);
583 102 : aEdge.getAllExtremumPositions(aExtremas);
584 :
585 102 : const sal_uInt32 nExtremaCount(aExtremas.size());
586 :
587 237 : for(sal_uInt32 c(0); c < nExtremaCount; c++)
588 : {
589 135 : aNewRange.expand(aEdge.interpolatePoint(aExtremas[c]));
590 102 : }
591 : }
592 : }
593 :
594 : // prepare next edge
595 435 : aEdge.setStartPoint(aEdge.getEndPoint());
596 35 : }
597 : }
598 : }
599 : }
600 :
601 82965 : const_cast< ImplBufferedData* >(this)->mpB2DRange.reset(new basegfx::B2DRange(aNewRange));
602 : }
603 :
604 83226 : return *mpB2DRange;
605 : }
606 : };
607 :
608 : //////////////////////////////////////////////////////////////////////////////
609 :
610 94570 : 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 83226 : const basegfx::B2DRange& getB2DRange(const basegfx::B2DPolygon& rSource) const
644 : {
645 83226 : if(!mpBufferedData)
646 : {
647 82965 : const_cast< ImplB2DPolygon* >(this)->mpBufferedData.reset(new ImplBufferedData);
648 : }
649 :
650 83226 : return mpBufferedData->getB2DRange(rSource);
651 : }
652 :
653 26 : ImplB2DPolygon()
654 : : maPoints(0),
655 : mpControlVector(),
656 : mpBufferedData(),
657 26 : mbIsClosed(false)
658 26 : {}
659 :
660 94712 : ImplB2DPolygon(const ImplB2DPolygon& rToBeCopied)
661 : : maPoints(rToBeCopied.maPoints),
662 : mpControlVector(),
663 : mpBufferedData(),
664 94712 : mbIsClosed(rToBeCopied.mbIsClosed)
665 : {
666 : // complete initialization using copy
667 94712 : if(rToBeCopied.mpControlVector && rToBeCopied.mpControlVector->isUsed())
668 : {
669 59 : mpControlVector.reset( new ControlVectorArray2D(*rToBeCopied.mpControlVector) );
670 : }
671 94712 : }
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 277655 : sal_uInt32 count() const
704 : {
705 277655 : return maPoints.count();
706 : }
707 :
708 100876 : bool isClosed() const
709 : {
710 100876 : return mbIsClosed;
711 : }
712 :
713 82450 : void setClosed(bool bNew)
714 : {
715 82450 : if(bNew != mbIsClosed)
716 : {
717 82450 : mpBufferedData.reset();
718 82450 : mbIsClosed = bNew;
719 : }
720 82450 : }
721 :
722 814 : bool operator==(const ImplB2DPolygon& rCandidate) const
723 : {
724 814 : if(mbIsClosed == rCandidate.mbIsClosed)
725 : {
726 712 : if(maPoints == rCandidate.maPoints)
727 : {
728 228 : bool bControlVectorsAreEqual(true);
729 :
730 228 : if(mpControlVector)
731 : {
732 9 : if(rCandidate.mpControlVector)
733 : {
734 9 : 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 219 : 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 228 : if(bControlVectorsAreEqual)
752 : {
753 228 : return true;
754 : }
755 : }
756 : }
757 :
758 586 : return false;
759 : }
760 :
761 1286446 : const basegfx::B2DPoint& getPoint(sal_uInt32 nIndex) const
762 : {
763 1286446 : return maPoints.getCoordinate(nIndex);
764 : }
765 :
766 157132 : void setPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue)
767 : {
768 157132 : mpBufferedData.reset();
769 157132 : maPoints.setCoordinate(nIndex, rValue);
770 157132 : }
771 :
772 15 : void reserve(sal_uInt32 nCount)
773 : {
774 15 : maPoints.reserve(nCount);
775 15 : }
776 :
777 162568 : void append(const basegfx::B2DPoint& rPoint)
778 : {
779 162568 : mpBufferedData.reset(); // TODO: is this needed?
780 162568 : const CoordinateData2D aCoordinate(rPoint);
781 162568 : maPoints.append(aCoordinate);
782 :
783 162568 : if(mpControlVector)
784 : {
785 753 : const ControlVectorPair2D aVectorPair;
786 753 : mpControlVector->append(aVectorPair);
787 162568 : }
788 162568 : }
789 :
790 53842 : void insert(sal_uInt32 nIndex, const basegfx::B2DPoint& rPoint, sal_uInt32 nCount)
791 : {
792 53842 : if(nCount)
793 : {
794 53842 : mpBufferedData.reset();
795 53842 : CoordinateData2D aCoordinate(rPoint);
796 53842 : maPoints.insert(nIndex, aCoordinate, nCount);
797 :
798 53842 : if(mpControlVector)
799 : {
800 2213 : ControlVectorPair2D aVectorPair;
801 2213 : mpControlVector->insert(nIndex, aVectorPair, nCount);
802 53842 : }
803 : }
804 53842 : }
805 :
806 7212 : const basegfx::B2DVector& getPrevControlVector(sal_uInt32 nIndex) const
807 : {
808 7212 : if(mpControlVector)
809 : {
810 7211 : return mpControlVector->getPrevVector(nIndex);
811 : }
812 : else
813 : {
814 1 : return basegfx::B2DVector::getEmptyVector();
815 : }
816 : }
817 :
818 2310 : void setPrevControlVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
819 : {
820 2310 : if(!mpControlVector)
821 : {
822 2 : if(!rValue.equalZero())
823 : {
824 1 : mpBufferedData.reset();
825 1 : mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
826 1 : mpControlVector->setPrevVector(nIndex, rValue);
827 : }
828 : }
829 : else
830 : {
831 2308 : mpBufferedData.reset();
832 2308 : mpControlVector->setPrevVector(nIndex, rValue);
833 :
834 2308 : if(!mpControlVector->isUsed())
835 0 : mpControlVector.reset();
836 : }
837 2310 : }
838 :
839 6893 : const basegfx::B2DVector& getNextControlVector(sal_uInt32 nIndex) const
840 : {
841 6893 : if(mpControlVector)
842 : {
843 6890 : return mpControlVector->getNextVector(nIndex);
844 : }
845 : else
846 : {
847 3 : return basegfx::B2DVector::getEmptyVector();
848 : }
849 : }
850 :
851 2225 : void setNextControlVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
852 : {
853 2225 : if(!mpControlVector)
854 : {
855 228 : if(!rValue.equalZero())
856 : {
857 228 : mpBufferedData.reset();
858 228 : mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
859 228 : mpControlVector->setNextVector(nIndex, rValue);
860 : }
861 : }
862 : else
863 : {
864 1997 : mpBufferedData.reset();
865 1997 : mpControlVector->setNextVector(nIndex, rValue);
866 :
867 1997 : if(!mpControlVector->isUsed())
868 0 : mpControlVector.reset();
869 : }
870 2225 : }
871 :
872 197909 : bool areControlPointsUsed() const
873 : {
874 197909 : 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 1 : void resetControlVectors()
884 : {
885 1 : mpBufferedData.reset();
886 1 : mpControlVector.reset();
887 1 : }
888 :
889 1 : void setControlVectors(sal_uInt32 nIndex, const basegfx::B2DVector& rPrev, const basegfx::B2DVector& rNext)
890 : {
891 1 : setPrevControlVector(nIndex, rPrev);
892 1 : setNextControlVector(nIndex, rNext);
893 1 : }
894 :
895 2210 : void appendBezierSegment(const basegfx::B2DVector& rNext, const basegfx::B2DVector& rPrev, const basegfx::B2DPoint& rPoint)
896 : {
897 2210 : mpBufferedData.reset();
898 2210 : const sal_uInt32 nCount(maPoints.count());
899 :
900 2210 : if(nCount)
901 : {
902 2209 : setNextControlVector(nCount - 1, rNext);
903 : }
904 :
905 2210 : insert(nCount, rPoint, 1);
906 2210 : setPrevControlVector(nCount, rPrev);
907 2210 : }
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 1222 : void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
940 : {
941 1222 : if(nCount)
942 : {
943 1222 : mpBufferedData.reset();
944 1222 : maPoints.remove(nIndex, nCount);
945 :
946 1222 : if(mpControlVector)
947 : {
948 213 : mpControlVector->remove(nIndex, nCount);
949 :
950 213 : if(!mpControlVector->isUsed())
951 0 : mpControlVector.reset();
952 : }
953 : }
954 1222 : }
955 :
956 587 : void flip()
957 : {
958 587 : if(maPoints.count() > 1)
959 : {
960 587 : mpBufferedData.reset();
961 :
962 : // flip points
963 587 : maPoints.flip(mbIsClosed);
964 :
965 587 : if(mpControlVector)
966 : {
967 : // flip control vector
968 0 : mpControlVector->flip(mbIsClosed);
969 : }
970 : }
971 587 : }
972 :
973 514 : bool hasDoublePoints() const
974 : {
975 514 : if(mbIsClosed)
976 : {
977 : // check for same start and end point
978 416 : const sal_uInt32 nIndex(maPoints.count() - 1);
979 :
980 416 : if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
981 : {
982 3 : 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 3 : return true;
992 : }
993 : }
994 : }
995 :
996 : // test for range
997 3575 : for(sal_uInt32 a(0); a < maPoints.count() - 1; a++)
998 : {
999 3090 : if(maPoints.getCoordinate(a) == maPoints.getCoordinate(a + 1))
1000 : {
1001 26 : 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 26 : return true;
1011 : }
1012 : }
1013 : }
1014 :
1015 485 : return false;
1016 : }
1017 :
1018 17 : void removeDoublePointsAtBeginEnd()
1019 : {
1020 : // Only remove DoublePoints at Begin and End when poly is closed
1021 17 : if(mbIsClosed)
1022 : {
1023 17 : mpBufferedData.reset();
1024 :
1025 17 : 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 17 : maPoints.removeDoublePointsAtBeginEnd();
1070 : }
1071 : }
1072 17 : }
1073 :
1074 17 : void removeDoublePointsWholeTrack()
1075 : {
1076 17 : mpBufferedData.reset();
1077 :
1078 17 : 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 17 : maPoints.removeDoublePointsWholeTrack();
1119 : }
1120 17 : }
1121 :
1122 3212 : void transform(const basegfx::B2DHomMatrix& rMatrix)
1123 : {
1124 3212 : mpBufferedData.reset();
1125 :
1126 3212 : if(mpControlVector)
1127 : {
1128 3611 : for(sal_uInt32 a(0); a < maPoints.count(); a++)
1129 : {
1130 3374 : basegfx::B2DPoint aCandidate = maPoints.getCoordinate(a);
1131 :
1132 3374 : if(mpControlVector->isUsed())
1133 : {
1134 3374 : const basegfx::B2DVector& rPrevVector(mpControlVector->getPrevVector(a));
1135 3374 : const basegfx::B2DVector& rNextVector(mpControlVector->getNextVector(a));
1136 :
1137 3374 : if(!rPrevVector.equalZero())
1138 : {
1139 2333 : basegfx::B2DVector aPrevVector(rMatrix * rPrevVector);
1140 2333 : mpControlVector->setPrevVector(a, aPrevVector);
1141 : }
1142 :
1143 3374 : if(!rNextVector.equalZero())
1144 : {
1145 2389 : basegfx::B2DVector aNextVector(rMatrix * rNextVector);
1146 2389 : mpControlVector->setNextVector(a, aNextVector);
1147 : }
1148 : }
1149 :
1150 3374 : aCandidate *= rMatrix;
1151 3374 : maPoints.setCoordinate(a, aCandidate);
1152 3374 : }
1153 :
1154 237 : if(!mpControlVector->isUsed())
1155 0 : mpControlVector.reset();
1156 : }
1157 : else
1158 : {
1159 2975 : maPoints.transform(rMatrix);
1160 : }
1161 3212 : }
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 89451 : B2DPolygon::B2DPolygon()
1196 89451 : : mpPolygon(DefaultPolygon::get())
1197 89451 : {}
1198 :
1199 366949 : B2DPolygon::B2DPolygon(const B2DPolygon& rPolygon)
1200 366949 : : mpPolygon(rPolygon.mpPolygon)
1201 366949 : {}
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 456200 : B2DPolygon::~B2DPolygon()
1212 : {
1213 456200 : }
1214 :
1215 1916 : B2DPolygon& B2DPolygon::operator=(const B2DPolygon& rPolygon)
1216 : {
1217 1916 : mpPolygon = rPolygon.mpPolygon;
1218 1916 : return *this;
1219 : }
1220 :
1221 30 : void B2DPolygon::makeUnique()
1222 : {
1223 30 : mpPolygon.make_unique();
1224 30 : }
1225 :
1226 835 : bool B2DPolygon::operator==(const B2DPolygon& rPolygon) const
1227 : {
1228 835 : if(mpPolygon.same_object(rPolygon.mpPolygon))
1229 21 : return true;
1230 :
1231 814 : return ((*mpPolygon) == (*rPolygon.mpPolygon));
1232 : }
1233 :
1234 555 : bool B2DPolygon::operator!=(const B2DPolygon& rPolygon) const
1235 : {
1236 555 : return !(*this == rPolygon);
1237 : }
1238 :
1239 214282 : sal_uInt32 B2DPolygon::count() const
1240 : {
1241 214282 : return mpPolygon->count();
1242 : }
1243 :
1244 1269919 : B2DPoint B2DPolygon::getB2DPoint(sal_uInt32 nIndex) const
1245 : {
1246 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1247 :
1248 1269919 : return mpPolygon->getPoint(nIndex);
1249 : }
1250 :
1251 158676 : void B2DPolygon::setB2DPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1252 : {
1253 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1254 :
1255 158676 : if(getB2DPoint(nIndex) != rValue)
1256 : {
1257 157132 : mpPolygon->setPoint(nIndex, rValue);
1258 : }
1259 158676 : }
1260 :
1261 15 : void B2DPolygon::reserve(sal_uInt32 nCount)
1262 : {
1263 15 : mpPolygon->reserve(nCount);
1264 15 : }
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 51625 : void B2DPolygon::append(const B2DPoint& rPoint, sal_uInt32 nCount)
1277 : {
1278 51625 : if(nCount)
1279 : {
1280 51625 : mpPolygon->insert(mpPolygon->count(), rPoint, nCount);
1281 : }
1282 51625 : }
1283 :
1284 162568 : void B2DPolygon::append(const B2DPoint& rPoint)
1285 : {
1286 162568 : mpPolygon->append(rPoint);
1287 162568 : }
1288 :
1289 4373 : B2DPoint B2DPolygon::getPrevControlPoint(sal_uInt32 nIndex) const
1290 : {
1291 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1292 :
1293 4373 : if(mpPolygon->areControlPointsUsed())
1294 : {
1295 4202 : return mpPolygon->getPoint(nIndex) + mpPolygon->getPrevControlVector(nIndex);
1296 : }
1297 : else
1298 : {
1299 171 : return mpPolygon->getPoint(nIndex);
1300 : }
1301 : }
1302 :
1303 4247 : B2DPoint B2DPolygon::getNextControlPoint(sal_uInt32 nIndex) const
1304 : {
1305 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1306 :
1307 4247 : if(mpPolygon->areControlPointsUsed())
1308 : {
1309 4088 : return mpPolygon->getPoint(nIndex) + mpPolygon->getNextControlVector(nIndex);
1310 : }
1311 : else
1312 : {
1313 159 : return mpPolygon->getPoint(nIndex);
1314 : }
1315 : }
1316 :
1317 99 : void B2DPolygon::setPrevControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1318 : {
1319 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1320 99 : const basegfx::B2DVector aNewVector(rValue - mpPolygon->getPoint(nIndex));
1321 :
1322 99 : if(mpPolygon->getPrevControlVector(nIndex) != aNewVector)
1323 : {
1324 99 : mpPolygon->setPrevControlVector(nIndex, aNewVector);
1325 99 : }
1326 99 : }
1327 :
1328 15 : void B2DPolygon::setNextControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1329 : {
1330 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1331 15 : const basegfx::B2DVector aNewVector(rValue - mpPolygon->getPoint(nIndex));
1332 :
1333 15 : if(mpPolygon->getNextControlVector(nIndex) != aNewVector)
1334 : {
1335 15 : mpPolygon->setNextControlVector(nIndex, aNewVector);
1336 15 : }
1337 15 : }
1338 :
1339 1 : 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 1 : const B2DPoint aPoint(mpPolygon->getPoint(nIndex));
1343 1 : const basegfx::B2DVector aNewPrev(rPrev - aPoint);
1344 1 : const basegfx::B2DVector aNewNext(rNext - aPoint);
1345 :
1346 1 : if(mpPolygon->getPrevControlVector(nIndex) != aNewPrev || mpPolygon->getNextControlVector(nIndex) != aNewNext)
1347 : {
1348 1 : mpPolygon->setControlVectors(nIndex, aNewPrev, aNewNext);
1349 1 : }
1350 1 : }
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 1 : void B2DPolygon::resetControlPoints()
1373 : {
1374 1 : if(mpPolygon->areControlPointsUsed())
1375 : {
1376 1 : mpPolygon->resetControlVectors();
1377 : }
1378 1 : }
1379 :
1380 2217 : void B2DPolygon::appendBezierSegment(
1381 : const B2DPoint& rNextControlPoint,
1382 : const B2DPoint& rPrevControlPoint,
1383 : const B2DPoint& rPoint)
1384 : {
1385 2217 : const B2DVector aNewNextVector(mpPolygon->count() ? B2DVector(rNextControlPoint - mpPolygon->getPoint(mpPolygon->count() - 1)) : B2DVector::getEmptyVector());
1386 2217 : const B2DVector aNewPrevVector(rPrevControlPoint - rPoint);
1387 :
1388 2217 : if(aNewNextVector.equalZero() && aNewPrevVector.equalZero())
1389 : {
1390 7 : mpPolygon->insert(mpPolygon->count(), rPoint, 1);
1391 : }
1392 : else
1393 : {
1394 2210 : mpPolygon->appendBezierSegment(aNewNextVector, aNewPrevVector, rPoint);
1395 2217 : }
1396 2217 : }
1397 :
1398 183525 : bool B2DPolygon::areControlPointsUsed() const
1399 : {
1400 183525 : return mpPolygon->areControlPointsUsed();
1401 : }
1402 :
1403 302 : bool B2DPolygon::isPrevControlPointUsed(sal_uInt32 nIndex) const
1404 : {
1405 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1406 :
1407 302 : return (mpPolygon->areControlPointsUsed() && !mpPolygon->getPrevControlVector(nIndex).equalZero());
1408 : }
1409 :
1410 181 : bool B2DPolygon::isNextControlPointUsed(sal_uInt32 nIndex) const
1411 : {
1412 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1413 :
1414 181 : return (mpPolygon->areControlPointsUsed() && !mpPolygon->getNextControlVector(nIndex).equalZero());
1415 : }
1416 :
1417 2523 : B2VectorContinuity B2DPolygon::getContinuityInPoint(sal_uInt32 nIndex) const
1418 : {
1419 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1420 :
1421 2523 : if(mpPolygon->areControlPointsUsed())
1422 : {
1423 2523 : const B2DVector& rPrev(mpPolygon->getPrevControlVector(nIndex));
1424 2523 : const B2DVector& rNext(mpPolygon->getNextControlVector(nIndex));
1425 :
1426 2523 : return getContinuity(rPrev, rNext);
1427 : }
1428 : else
1429 : {
1430 0 : return CONTINUITY_NONE;
1431 : }
1432 : }
1433 :
1434 2819 : void B2DPolygon::getBezierSegment(sal_uInt32 nIndex, B2DCubicBezier& rTarget) const
1435 : {
1436 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1437 2819 : const bool bNextIndexValidWithoutClose(nIndex + 1 < mpPolygon->count());
1438 :
1439 2819 : if(bNextIndexValidWithoutClose || mpPolygon->isClosed())
1440 : {
1441 2757 : const sal_uInt32 nNextIndex(bNextIndexValidWithoutClose ? nIndex + 1 : 0);
1442 2757 : rTarget.setStartPoint(mpPolygon->getPoint(nIndex));
1443 2757 : rTarget.setEndPoint(mpPolygon->getPoint(nNextIndex));
1444 :
1445 2757 : if(mpPolygon->areControlPointsUsed())
1446 : {
1447 109 : rTarget.setControlPointA(rTarget.getStartPoint() + mpPolygon->getNextControlVector(nIndex));
1448 109 : rTarget.setControlPointB(rTarget.getEndPoint() + mpPolygon->getPrevControlVector(nNextIndex));
1449 : }
1450 : else
1451 : {
1452 : // no bezier, reset control poins at rTarget
1453 2648 : rTarget.setControlPointA(rTarget.getStartPoint());
1454 2648 : rTarget.setControlPointB(rTarget.getEndPoint());
1455 : }
1456 : }
1457 : else
1458 : {
1459 : // no valid edge at all, reset rTarget to current point
1460 62 : const B2DPoint aPoint(mpPolygon->getPoint(nIndex));
1461 62 : rTarget.setStartPoint(aPoint);
1462 62 : rTarget.setEndPoint(aPoint);
1463 62 : rTarget.setControlPointA(aPoint);
1464 62 : rTarget.setControlPointB(aPoint);
1465 : }
1466 2819 : }
1467 :
1468 0 : B2DPolygon B2DPolygon::getDefaultAdaptiveSubdivision() const
1469 : {
1470 0 : return mpPolygon->getDefaultAdaptiveSubdivision(*this);
1471 : }
1472 :
1473 83226 : B2DRange B2DPolygon::getB2DRange() const
1474 : {
1475 83226 : 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 1222 : void B2DPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
1501 : {
1502 : OSL_ENSURE(nIndex + nCount <= mpPolygon->count(), "B2DPolygon Remove outside range (!)");
1503 :
1504 1222 : if(nCount)
1505 : {
1506 1222 : mpPolygon->remove(nIndex, nCount);
1507 : }
1508 1222 : }
1509 :
1510 1977 : void B2DPolygon::clear()
1511 : {
1512 1977 : mpPolygon = DefaultPolygon::get();
1513 1977 : }
1514 :
1515 100359 : bool B2DPolygon::isClosed() const
1516 : {
1517 100359 : return mpPolygon->isClosed();
1518 : }
1519 :
1520 85342 : void B2DPolygon::setClosed(bool bNew)
1521 : {
1522 85342 : if(isClosed() != bNew)
1523 : {
1524 82450 : mpPolygon->setClosed(bNew);
1525 : }
1526 85342 : }
1527 :
1528 587 : void B2DPolygon::flip()
1529 : {
1530 587 : if(count() > 1)
1531 : {
1532 587 : mpPolygon->flip();
1533 : }
1534 587 : }
1535 :
1536 517 : bool B2DPolygon::hasDoublePoints() const
1537 : {
1538 517 : return (mpPolygon->count() > 1 && mpPolygon->hasDoublePoints());
1539 : }
1540 :
1541 128 : void B2DPolygon::removeDoublePoints()
1542 : {
1543 128 : if(hasDoublePoints())
1544 : {
1545 17 : mpPolygon->removeDoublePointsAtBeginEnd();
1546 17 : mpPolygon->removeDoublePointsWholeTrack();
1547 : }
1548 128 : }
1549 :
1550 3972 : void B2DPolygon::transform(const B2DHomMatrix& rMatrix)
1551 : {
1552 3972 : if(mpPolygon->count() && !rMatrix.isIdentity())
1553 : {
1554 3212 : mpPolygon->transform(rMatrix);
1555 : }
1556 3972 : }
1557 :
1558 : } // end of namespace basegfx
1559 :
1560 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|