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 95103056 : struct CoordinateData2D : public basegfx::B2DPoint
33 : {
34 : public:
35 0 : CoordinateData2D() {}
36 :
37 15077203 : explicit CoordinateData2D(const basegfx::B2DPoint& rData)
38 15077203 : : B2DPoint(rData)
39 15077203 : {}
40 :
41 12104480 : CoordinateData2D& operator=(const basegfx::B2DPoint& rData)
42 : {
43 12104480 : B2DPoint::operator=(rData);
44 12104480 : return *this;
45 : }
46 :
47 6477566 : void transform(const basegfx::B2DHomMatrix& rMatrix)
48 : {
49 6477566 : *this *= rMatrix;
50 6477566 : }
51 : };
52 :
53 6126886 : class CoordinateDataArray2D
54 : {
55 : typedef ::std::vector< CoordinateData2D > CoordinateData2DVector;
56 :
57 : CoordinateData2DVector maVector;
58 :
59 : public:
60 214 : explicit CoordinateDataArray2D(sal_uInt32 nCount)
61 214 : : maVector(nCount)
62 : {
63 214 : }
64 :
65 6136226 : explicit CoordinateDataArray2D(const CoordinateDataArray2D& rOriginal)
66 6136226 : : maVector(rOriginal.maVector)
67 : {
68 6136226 : }
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 20241803 : sal_uInt32 count() const
76 : {
77 20241803 : return maVector.size();
78 : }
79 :
80 45431 : bool operator==(const CoordinateDataArray2D& rCandidate) const
81 : {
82 45431 : return (maVector == rCandidate.maVector);
83 : }
84 :
85 147386339 : const basegfx::B2DPoint& getCoordinate(sal_uInt32 nIndex) const
86 : {
87 147386339 : return maVector[nIndex];
88 : }
89 :
90 12104480 : void setCoordinate(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue)
91 : {
92 12104480 : maVector[nIndex] = rValue;
93 12104480 : }
94 :
95 60314 : void reserve(sal_uInt32 nCount)
96 : {
97 60314 : maVector.reserve(nCount);
98 60314 : }
99 :
100 11566278 : void append(const CoordinateData2D& rValue)
101 : {
102 11566278 : maVector.push_back(rValue);
103 11566278 : }
104 :
105 3510925 : void insert(sal_uInt32 nIndex, const CoordinateData2D& rValue, sal_uInt32 nCount)
106 : {
107 3510925 : if(nCount)
108 : {
109 : // add nCount copies of rValue
110 3510925 : CoordinateData2DVector::iterator aIndex(maVector.begin());
111 3510925 : aIndex += nIndex;
112 3510925 : maVector.insert(aIndex, nCount, rValue);
113 : }
114 3510925 : }
115 :
116 4934 : void insert(sal_uInt32 nIndex, const CoordinateDataArray2D& rSource)
117 : {
118 4934 : const sal_uInt32 nCount(rSource.maVector.size());
119 :
120 4934 : if(nCount)
121 : {
122 : // insert data
123 4934 : CoordinateData2DVector::iterator aIndex(maVector.begin());
124 4934 : aIndex += nIndex;
125 4934 : CoordinateData2DVector::const_iterator aStart(rSource.maVector.begin());
126 4934 : CoordinateData2DVector::const_iterator aEnd(rSource.maVector.end());
127 4934 : maVector.insert(aIndex, aStart, aEnd);
128 : }
129 4934 : }
130 :
131 61069 : void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
132 : {
133 61069 : if(nCount)
134 : {
135 : // remove point data
136 61069 : CoordinateData2DVector::iterator aStart(maVector.begin());
137 61069 : aStart += nIndex;
138 61069 : const CoordinateData2DVector::iterator aEnd(aStart + nCount);
139 61069 : maVector.erase(aStart, aEnd);
140 : }
141 61069 : }
142 :
143 765 : void flip(bool bIsClosed)
144 : {
145 765 : 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 765 : const sal_uInt32 nHalfSize(bIsClosed ? (maVector.size() - 1) >> 1 : maVector.size() >> 1);
150 765 : CoordinateData2DVector::iterator aStart(bIsClosed ? maVector.begin() + 1 : maVector.begin());
151 765 : CoordinateData2DVector::iterator aEnd(maVector.end() - 1);
152 :
153 2206 : for(sal_uInt32 a(0); a < nHalfSize; a++)
154 : {
155 1441 : ::std::swap(*aStart, *aEnd);
156 1441 : ++aStart;
157 1441 : --aEnd;
158 : }
159 : }
160 765 : }
161 :
162 722 : void removeDoublePointsAtBeginEnd()
163 : {
164 : // remove from end as long as there are at least two points
165 : // and begin/end are equal
166 2021 : while((maVector.size() > 1) && (maVector[0] == maVector[maVector.size() - 1]))
167 : {
168 577 : maVector.pop_back();
169 : }
170 722 : }
171 :
172 1375 : void removeDoublePointsWholeTrack()
173 : {
174 1375 : 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 32018 : while((maVector.size() > 1) && (nIndex <= maVector.size() - 2))
179 : {
180 29268 : if(maVector[nIndex] == maVector[nIndex + 1])
181 : {
182 : // if next is same as index, delete next
183 1854 : maVector.erase(maVector.begin() + (nIndex + 1));
184 : }
185 : else
186 : {
187 : // if different, step forward
188 27414 : nIndex++;
189 : }
190 : }
191 1375 : }
192 :
193 801007 : void transform(const basegfx::B2DHomMatrix& rMatrix)
194 : {
195 801007 : CoordinateData2DVector::iterator aStart(maVector.begin());
196 801007 : CoordinateData2DVector::iterator aEnd(maVector.end());
197 :
198 7278573 : for(; aStart != aEnd; ++aStart)
199 : {
200 6477566 : aStart->transform(rMatrix);
201 : }
202 801007 : }
203 : };
204 :
205 2196561 : class ControlVectorPair2D
206 : {
207 : basegfx::B2DVector maPrevVector;
208 : basegfx::B2DVector maNextVector;
209 :
210 : public:
211 242115 : explicit ControlVectorPair2D() {}
212 :
213 2800056 : const basegfx::B2DVector& getPrevVector() const
214 : {
215 2800056 : return maPrevVector;
216 : }
217 :
218 449960 : void setPrevVector(const basegfx::B2DVector& rValue)
219 : {
220 449960 : if(rValue != maPrevVector)
221 380182 : maPrevVector = rValue;
222 449960 : }
223 :
224 2733835 : const basegfx::B2DVector& getNextVector() const
225 : {
226 2733835 : return maNextVector;
227 : }
228 :
229 442392 : void setNextVector(const basegfx::B2DVector& rValue)
230 : {
231 442392 : if(rValue != maNextVector)
232 372430 : maNextVector = rValue;
233 442392 : }
234 :
235 6287 : bool operator==(const ControlVectorPair2D& rData) const
236 : {
237 6287 : return (maPrevVector == rData.getPrevVector() && maNextVector == rData.getNextVector());
238 : }
239 :
240 602 : void flip()
241 : {
242 602 : ::std::swap(maPrevVector, maNextVector);
243 602 : }
244 : };
245 :
246 152941 : class ControlVectorArray2D
247 : {
248 : typedef ::std::vector< ControlVectorPair2D > ControlVectorPair2DVector;
249 :
250 : ControlVectorPair2DVector maVector;
251 : sal_uInt32 mnUsedVectors;
252 :
253 : public:
254 30203 : explicit ControlVectorArray2D(sal_uInt32 nCount)
255 : : maVector(nCount),
256 30203 : mnUsedVectors(0)
257 30203 : {}
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 1449 : bool operator==(const ControlVectorArray2D& rCandidate) const
282 : {
283 1449 : return (maVector == rCandidate.maVector);
284 : }
285 :
286 3362600 : bool isUsed() const
287 : {
288 3362600 : return (0 != mnUsedVectors);
289 : }
290 :
291 2124745 : const basegfx::B2DVector& getPrevVector(sal_uInt32 nIndex) const
292 : {
293 2124745 : return maVector[nIndex].getPrevVector();
294 : }
295 :
296 452160 : void setPrevVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
297 : {
298 452160 : bool bWasUsed(mnUsedVectors && !maVector[nIndex].getPrevVector().equalZero());
299 452160 : bool bIsUsed(!rValue.equalZero());
300 :
301 452160 : if(bWasUsed)
302 : {
303 318455 : if(bIsUsed)
304 : {
305 318435 : maVector[nIndex].setPrevVector(rValue);
306 : }
307 : else
308 : {
309 20 : maVector[nIndex].setPrevVector(basegfx::B2DVector::getEmptyVector());
310 20 : mnUsedVectors--;
311 : }
312 : }
313 : else
314 : {
315 133705 : if(bIsUsed)
316 : {
317 131505 : maVector[nIndex].setPrevVector(rValue);
318 131505 : mnUsedVectors++;
319 : }
320 : }
321 452160 : }
322 :
323 2094096 : const basegfx::B2DVector& getNextVector(sal_uInt32 nIndex) const
324 : {
325 2094096 : return maVector[nIndex].getNextVector();
326 : }
327 :
328 443999 : void setNextVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
329 : {
330 443999 : bool bWasUsed(mnUsedVectors && !maVector[nIndex].getNextVector().equalZero());
331 443999 : bool bIsUsed(!rValue.equalZero());
332 :
333 443999 : if(bWasUsed)
334 : {
335 318578 : if(bIsUsed)
336 : {
337 318578 : 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 125421 : if(bIsUsed)
348 : {
349 123814 : maVector[nIndex].setNextVector(rValue);
350 123814 : mnUsedVectors++;
351 : }
352 : }
353 443999 : }
354 :
355 76086 : void append(const ControlVectorPair2D& rValue)
356 : {
357 76086 : maVector.push_back(rValue);
358 :
359 76086 : if(!rValue.getPrevVector().equalZero())
360 0 : mnUsedVectors += 1;
361 :
362 76086 : if(!rValue.getNextVector().equalZero())
363 0 : mnUsedVectors += 1;
364 76086 : }
365 :
366 124448 : void insert(sal_uInt32 nIndex, const ControlVectorPair2D& rValue, sal_uInt32 nCount)
367 : {
368 124448 : if(nCount)
369 : {
370 : // add nCount copies of rValue
371 124448 : ControlVectorPair2DVector::iterator aIndex(maVector.begin());
372 124448 : aIndex += nIndex;
373 124448 : maVector.insert(aIndex, nCount, rValue);
374 :
375 124448 : if(!rValue.getPrevVector().equalZero())
376 0 : mnUsedVectors += nCount;
377 :
378 124448 : if(!rValue.getNextVector().equalZero())
379 0 : mnUsedVectors += nCount;
380 : }
381 124448 : }
382 :
383 295 : void insert(sal_uInt32 nIndex, const ControlVectorArray2D& rSource)
384 : {
385 295 : const sal_uInt32 nCount(rSource.maVector.size());
386 :
387 295 : if(nCount)
388 : {
389 : // insert data
390 295 : ControlVectorPair2DVector::iterator aIndex(maVector.begin());
391 295 : aIndex += nIndex;
392 295 : ControlVectorPair2DVector::const_iterator aStart(rSource.maVector.begin());
393 295 : ControlVectorPair2DVector::const_iterator aEnd(rSource.maVector.end());
394 295 : maVector.insert(aIndex, aStart, aEnd);
395 :
396 2002 : for(; aStart != aEnd; ++aStart)
397 : {
398 1707 : if(!aStart->getPrevVector().equalZero())
399 1376 : mnUsedVectors++;
400 :
401 1707 : if(!aStart->getNextVector().equalZero())
402 1376 : mnUsedVectors++;
403 : }
404 : }
405 295 : }
406 :
407 15912 : void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
408 : {
409 15912 : if(nCount)
410 : {
411 15912 : const ControlVectorPair2DVector::iterator aDeleteStart(maVector.begin() + nIndex);
412 15912 : const ControlVectorPair2DVector::iterator aDeleteEnd(aDeleteStart + nCount);
413 15912 : ControlVectorPair2DVector::const_iterator aStart(aDeleteStart);
414 :
415 31860 : for(; mnUsedVectors && aStart != aDeleteEnd; ++aStart)
416 : {
417 15948 : if(!aStart->getPrevVector().equalZero())
418 7352 : mnUsedVectors--;
419 :
420 15948 : if(mnUsedVectors && !aStart->getNextVector().equalZero())
421 2 : mnUsedVectors--;
422 : }
423 :
424 : // remove point data
425 15912 : maVector.erase(aDeleteStart, aDeleteEnd);
426 : }
427 15912 : }
428 :
429 104 : void flip(bool bIsClosed)
430 : {
431 104 : 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 104 : const sal_uInt32 nHalfSize(bIsClosed ? (maVector.size() - 1) >> 1 : maVector.size() >> 1);
436 104 : ControlVectorPair2DVector::iterator aStart(bIsClosed ? maVector.begin() + 1 : maVector.begin());
437 104 : ControlVectorPair2DVector::iterator aEnd(maVector.end() - 1);
438 :
439 378 : for(sal_uInt32 a(0); a < nHalfSize; a++)
440 : {
441 : // swap Prev and Next
442 274 : aStart->flip();
443 274 : aEnd->flip();
444 :
445 : // swap entries
446 274 : ::std::swap(*aStart, *aEnd);
447 :
448 274 : ++aStart;
449 274 : --aEnd;
450 : }
451 :
452 104 : if(aStart == aEnd)
453 : {
454 : // swap Prev and Next at middle element (if exists)
455 52 : aStart->flip();
456 : }
457 :
458 104 : if(bIsClosed)
459 : {
460 : // swap Prev and Next at start element
461 2 : maVector.begin()->flip();
462 : }
463 : }
464 104 : }
465 : };
466 :
467 5088723 : 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 5092322 : ImplBufferedData()
478 : : mpDefaultSubdivision(),
479 5092322 : mpB2DRange()
480 5092322 : {}
481 :
482 5421 : const basegfx::B2DPolygon& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon& rSource) const
483 : {
484 5421 : if(!mpDefaultSubdivision)
485 : {
486 2591 : const_cast< ImplBufferedData* >(this)->mpDefaultSubdivision.reset(new basegfx::B2DPolygon(basegfx::tools::adaptiveSubdivideByCount(rSource, 9)));
487 : }
488 :
489 5421 : return *mpDefaultSubdivision;
490 : }
491 :
492 5579166 : const basegfx::B2DRange& getB2DRange(const basegfx::B2DPolygon& rSource) const
493 : {
494 5579166 : if(!mpB2DRange)
495 : {
496 5092247 : basegfx::B2DRange aNewRange;
497 5092247 : const sal_uInt32 nPointCount(rSource.count());
498 :
499 5092247 : if(nPointCount)
500 : {
501 29151390 : for(sal_uInt32 a(0); a < nPointCount; a++)
502 : {
503 24059143 : aNewRange.expand(rSource.getB2DPoint(a));
504 : }
505 :
506 5092247 : if(rSource.areControlPointsUsed())
507 : {
508 41315 : const sal_uInt32 nEdgeCount(rSource.isClosed() ? nPointCount : nPointCount - 1);
509 :
510 41315 : if(nEdgeCount)
511 : {
512 41315 : basegfx::B2DCubicBezier aEdge;
513 41315 : aEdge.setStartPoint(rSource.getB2DPoint(0));
514 :
515 330047 : for(sal_uInt32 b(0); b < nEdgeCount; b++)
516 : {
517 288732 : const sal_uInt32 nNextIndex((b + 1) % nPointCount);
518 288732 : aEdge.setControlPointA(rSource.getNextControlPoint(b));
519 288732 : aEdge.setControlPointB(rSource.getPrevControlPoint(nNextIndex));
520 288732 : aEdge.setEndPoint(rSource.getB2DPoint(nNextIndex));
521 :
522 288732 : if(aEdge.isBezier())
523 : {
524 152492 : const basegfx::B2DRange aBezierRangeWithControlPoints(aEdge.getRange());
525 :
526 152492 : 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 23993 : ::std::vector< double > aExtremas;
534 :
535 23993 : aExtremas.reserve(4);
536 23993 : aEdge.getAllExtremumPositions(aExtremas);
537 :
538 23993 : const sal_uInt32 nExtremaCount(aExtremas.size());
539 :
540 47383 : for(sal_uInt32 c(0); c < nExtremaCount; c++)
541 : {
542 23390 : aNewRange.expand(aEdge.interpolatePoint(aExtremas[c]));
543 23993 : }
544 : }
545 : }
546 :
547 : // prepare next edge
548 288732 : aEdge.setStartPoint(aEdge.getEndPoint());
549 41315 : }
550 : }
551 : }
552 : }
553 :
554 5092247 : const_cast< ImplBufferedData* >(this)->mpB2DRange.reset(new basegfx::B2DRange(aNewRange));
555 : }
556 :
557 5579166 : return *mpB2DRange;
558 : }
559 : };
560 :
561 6126886 : 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 5471 : const basegfx::B2DPolygon& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon& rSource) const
580 : {
581 5471 : if(!mpControlVector || !mpControlVector->isUsed())
582 : {
583 50 : return rSource;
584 : }
585 :
586 5421 : if(!mpBufferedData)
587 : {
588 556 : const_cast< ImplB2DPolygon* >(this)->mpBufferedData.reset(new ImplBufferedData);
589 : }
590 :
591 5421 : return mpBufferedData->getDefaultAdaptiveSubdivision(rSource);
592 : }
593 :
594 5579166 : const basegfx::B2DRange& getB2DRange(const basegfx::B2DPolygon& rSource) const
595 : {
596 5579166 : if(!mpBufferedData)
597 : {
598 5091766 : const_cast< ImplB2DPolygon* >(this)->mpBufferedData.reset(new ImplBufferedData);
599 : }
600 :
601 5579166 : return mpBufferedData->getB2DRange(rSource);
602 : }
603 :
604 214 : ImplB2DPolygon()
605 : : maPoints(0),
606 : mpControlVector(),
607 : mpBufferedData(),
608 214 : mbIsClosed(false)
609 214 : {}
610 :
611 6136226 : ImplB2DPolygon(const ImplB2DPolygon& rToBeCopied)
612 : : maPoints(rToBeCopied.maPoints),
613 : mpControlVector(),
614 : mpBufferedData(),
615 6136226 : mbIsClosed(rToBeCopied.mbIsClosed)
616 : {
617 : // complete initialization using copy
618 6136226 : if(rToBeCopied.mpControlVector && rToBeCopied.mpControlVector->isUsed())
619 : {
620 61388 : mpControlVector.reset( new ControlVectorArray2D(*rToBeCopied.mpControlVector) );
621 : }
622 6136226 : }
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 19335397 : sal_uInt32 count() const
643 : {
644 19335397 : return maPoints.count();
645 : }
646 :
647 6321963 : bool isClosed() const
648 : {
649 6321963 : return mbIsClosed;
650 : }
651 :
652 4916775 : void setClosed(bool bNew)
653 : {
654 4916775 : if(bNew != mbIsClosed)
655 : {
656 4916775 : mpBufferedData.reset();
657 4916775 : mbIsClosed = bNew;
658 : }
659 4916775 : }
660 :
661 47887 : bool operator==(const ImplB2DPolygon& rCandidate) const
662 : {
663 47887 : if(mbIsClosed == rCandidate.mbIsClosed)
664 : {
665 45431 : if(maPoints == rCandidate.maPoints)
666 : {
667 26985 : bool bControlVectorsAreEqual(true);
668 :
669 26985 : if(mpControlVector)
670 : {
671 1449 : if(rCandidate.mpControlVector)
672 : {
673 1449 : 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 25536 : if(rCandidate.mpControlVector)
684 : {
685 : // we have no control vector, so it's assumed all unused.
686 56 : bControlVectorsAreEqual = !rCandidate.mpControlVector->isUsed();
687 : }
688 : }
689 :
690 26985 : if(bControlVectorsAreEqual)
691 : {
692 26929 : return true;
693 : }
694 : }
695 : }
696 :
697 20958 : return false;
698 : }
699 :
700 146680518 : const basegfx::B2DPoint& getPoint(sal_uInt32 nIndex) const
701 : {
702 146680518 : return maPoints.getCoordinate(nIndex);
703 : }
704 :
705 11594941 : void setPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue)
706 : {
707 11594941 : mpBufferedData.reset();
708 11594941 : maPoints.setCoordinate(nIndex, rValue);
709 11594941 : }
710 :
711 60314 : void reserve(sal_uInt32 nCount)
712 : {
713 60314 : maPoints.reserve(nCount);
714 60314 : }
715 :
716 11566278 : void append(const basegfx::B2DPoint& rPoint)
717 : {
718 11566278 : mpBufferedData.reset(); // TODO: is this needed?
719 11566278 : const CoordinateData2D aCoordinate(rPoint);
720 11566278 : maPoints.append(aCoordinate);
721 :
722 11566278 : if(mpControlVector)
723 : {
724 76086 : const ControlVectorPair2D aVectorPair;
725 76086 : mpControlVector->append(aVectorPair);
726 11566278 : }
727 11566278 : }
728 :
729 3510925 : void insert(sal_uInt32 nIndex, const basegfx::B2DPoint& rPoint, sal_uInt32 nCount)
730 : {
731 3510925 : if(nCount)
732 : {
733 3510925 : mpBufferedData.reset();
734 3510925 : CoordinateData2D aCoordinate(rPoint);
735 3510925 : maPoints.insert(nIndex, aCoordinate, nCount);
736 :
737 3510925 : if(mpControlVector)
738 : {
739 124440 : ControlVectorPair2D aVectorPair;
740 124440 : mpControlVector->insert(nIndex, aVectorPair, nCount);
741 3510925 : }
742 : }
743 3510925 : }
744 :
745 1598707 : const basegfx::B2DVector& getPrevControlVector(sal_uInt32 nIndex) const
746 : {
747 1598707 : if(mpControlVector)
748 : {
749 1598292 : return mpControlVector->getPrevVector(nIndex);
750 : }
751 : else
752 : {
753 415 : return basegfx::B2DVector::getEmptyVector();
754 : }
755 : }
756 :
757 135761 : void setPrevControlVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
758 : {
759 135761 : if(!mpControlVector)
760 : {
761 1327 : if(!rValue.equalZero())
762 : {
763 1325 : mpBufferedData.reset();
764 1325 : mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
765 1325 : mpControlVector->setPrevVector(nIndex, rValue);
766 : }
767 : }
768 : else
769 : {
770 134434 : mpBufferedData.reset();
771 134434 : mpControlVector->setPrevVector(nIndex, rValue);
772 :
773 134434 : if(!mpControlVector->isUsed())
774 0 : mpControlVector.reset();
775 : }
776 135761 : }
777 :
778 1575737 : const basegfx::B2DVector& getNextControlVector(sal_uInt32 nIndex) const
779 : {
780 1575737 : if(mpControlVector)
781 : {
782 1575570 : return mpControlVector->getNextVector(nIndex);
783 : }
784 : else
785 : {
786 167 : return basegfx::B2DVector::getEmptyVector();
787 : }
788 : }
789 :
790 131093 : void setNextControlVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
791 : {
792 131093 : if(!mpControlVector)
793 : {
794 29646 : if(!rValue.equalZero())
795 : {
796 28736 : mpBufferedData.reset();
797 28736 : mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
798 28736 : mpControlVector->setNextVector(nIndex, rValue);
799 : }
800 : }
801 : else
802 : {
803 101447 : mpBufferedData.reset();
804 101447 : mpControlVector->setNextVector(nIndex, rValue);
805 :
806 101447 : if(!mpControlVector->isUsed())
807 0 : mpControlVector.reset();
808 : }
809 131093 : }
810 :
811 14913840 : bool areControlPointsUsed() const
812 : {
813 14913840 : return (mpControlVector && mpControlVector->isUsed());
814 : }
815 :
816 2 : void resetControlVectors()
817 : {
818 2 : mpBufferedData.reset();
819 2 : mpControlVector.reset();
820 2 : }
821 :
822 2 : void setControlVectors(sal_uInt32 nIndex, const basegfx::B2DVector& rPrev, const basegfx::B2DVector& rNext)
823 : {
824 2 : setPrevControlVector(nIndex, rPrev);
825 2 : setNextControlVector(nIndex, rNext);
826 2 : }
827 :
828 123882 : void appendBezierSegment(const basegfx::B2DVector& rNext, const basegfx::B2DVector& rPrev, const basegfx::B2DPoint& rPoint)
829 : {
830 123882 : mpBufferedData.reset();
831 123882 : const sal_uInt32 nCount(maPoints.count());
832 :
833 123882 : if(nCount)
834 : {
835 123880 : setNextControlVector(nCount - 1, rNext);
836 : }
837 :
838 123882 : insert(nCount, rPoint, 1);
839 123882 : setPrevControlVector(nCount, rPrev);
840 123882 : }
841 :
842 4934 : void insert(sal_uInt32 nIndex, const ImplB2DPolygon& rSource)
843 : {
844 4934 : const sal_uInt32 nCount(rSource.maPoints.count());
845 :
846 4934 : if(nCount)
847 : {
848 4934 : mpBufferedData.reset();
849 :
850 4934 : if(rSource.mpControlVector && rSource.mpControlVector->isUsed() && !mpControlVector)
851 : {
852 142 : mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
853 : }
854 :
855 4934 : maPoints.insert(nIndex, rSource.maPoints);
856 :
857 4934 : if(rSource.mpControlVector)
858 : {
859 295 : mpControlVector->insert(nIndex, *rSource.mpControlVector);
860 :
861 295 : if(!mpControlVector->isUsed())
862 0 : mpControlVector.reset();
863 : }
864 4639 : else if(mpControlVector)
865 : {
866 8 : ControlVectorPair2D aVectorPair;
867 8 : mpControlVector->insert(nIndex, aVectorPair, nCount);
868 : }
869 : }
870 4934 : }
871 :
872 61069 : void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
873 : {
874 61069 : if(nCount)
875 : {
876 61069 : mpBufferedData.reset();
877 61069 : maPoints.remove(nIndex, nCount);
878 :
879 61069 : if(mpControlVector)
880 : {
881 15912 : mpControlVector->remove(nIndex, nCount);
882 :
883 15912 : if(!mpControlVector->isUsed())
884 0 : mpControlVector.reset();
885 : }
886 : }
887 61069 : }
888 :
889 765 : void flip()
890 : {
891 765 : if(maPoints.count() > 1)
892 : {
893 765 : mpBufferedData.reset();
894 :
895 : // flip points
896 765 : maPoints.flip(mbIsClosed);
897 :
898 765 : if(mpControlVector)
899 : {
900 : // flip control vector
901 104 : mpControlVector->flip(mbIsClosed);
902 : }
903 : }
904 765 : }
905 :
906 32017 : bool hasDoublePoints() const
907 : {
908 32017 : if(mbIsClosed)
909 : {
910 : // check for same start and end point
911 9156 : const sal_uInt32 nIndex(maPoints.count() - 1);
912 :
913 9156 : if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
914 : {
915 3190 : if(mpControlVector)
916 : {
917 2667 : if(mpControlVector->getNextVector(nIndex).equalZero() && mpControlVector->getPrevVector(0).equalZero())
918 : {
919 2667 : return true;
920 : }
921 : }
922 : else
923 : {
924 523 : return true;
925 : }
926 : }
927 : }
928 :
929 : // test for range
930 84305 : for(sal_uInt32 a(0); a < maPoints.count() - 1; a++)
931 : {
932 57535 : if(maPoints.getCoordinate(a) == maPoints.getCoordinate(a + 1))
933 : {
934 2063 : if(mpControlVector)
935 : {
936 1106 : if(mpControlVector->getNextVector(a).equalZero() && mpControlVector->getPrevVector(a + 1).equalZero())
937 : {
938 1100 : return true;
939 : }
940 : }
941 : else
942 : {
943 957 : return true;
944 : }
945 : }
946 : }
947 :
948 26770 : return false;
949 : }
950 :
951 4683 : void removeDoublePointsAtBeginEnd()
952 : {
953 : // Only remove DoublePoints at Begin and End when poly is closed
954 4683 : if(mbIsClosed)
955 : {
956 3004 : mpBufferedData.reset();
957 :
958 3004 : if(mpControlVector)
959 : {
960 : bool bRemove;
961 :
962 5314 : do
963 : {
964 5314 : bRemove = false;
965 :
966 5314 : if(maPoints.count() > 1)
967 : {
968 5314 : const sal_uInt32 nIndex(maPoints.count() - 1);
969 :
970 5314 : if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
971 : {
972 3034 : if(mpControlVector)
973 : {
974 3034 : if(mpControlVector->getNextVector(nIndex).equalZero() && mpControlVector->getPrevVector(0).equalZero())
975 : {
976 3032 : bRemove = true;
977 : }
978 : }
979 : else
980 : {
981 0 : bRemove = true;
982 : }
983 : }
984 : }
985 :
986 5314 : if(bRemove)
987 : {
988 3032 : const sal_uInt32 nIndex(maPoints.count() - 1);
989 :
990 3032 : if(mpControlVector && !mpControlVector->getPrevVector(nIndex).equalZero())
991 : {
992 1309 : mpControlVector->setPrevVector(0, mpControlVector->getPrevVector(nIndex));
993 : }
994 :
995 3032 : remove(nIndex, 1);
996 : }
997 : }
998 : while(bRemove);
999 : }
1000 : else
1001 : {
1002 722 : maPoints.removeDoublePointsAtBeginEnd();
1003 : }
1004 : }
1005 4683 : }
1006 :
1007 4683 : void removeDoublePointsWholeTrack()
1008 : {
1009 4683 : mpBufferedData.reset();
1010 :
1011 4683 : if(mpControlVector)
1012 : {
1013 3308 : 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 32752 : while((maPoints.count() > 1) && (nIndex <= maPoints.count() - 2))
1018 : {
1019 26136 : bool bRemove(maPoints.getCoordinate(nIndex) == maPoints.getCoordinate(nIndex + 1));
1020 :
1021 26136 : if(bRemove)
1022 : {
1023 2180 : if(mpControlVector)
1024 : {
1025 2180 : if(!mpControlVector->getNextVector(nIndex).equalZero() || !mpControlVector->getPrevVector(nIndex + 1).equalZero())
1026 : {
1027 3 : bRemove = false;
1028 : }
1029 : }
1030 : }
1031 :
1032 26136 : if(bRemove)
1033 : {
1034 2177 : if(mpControlVector && !mpControlVector->getPrevVector(nIndex).equalZero())
1035 : {
1036 1420 : 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 2177 : remove(nIndex, 1);
1041 : }
1042 : else
1043 : {
1044 : // if different, step forward
1045 23959 : nIndex++;
1046 : }
1047 : }
1048 : }
1049 : else
1050 : {
1051 1375 : maPoints.removeDoublePointsWholeTrack();
1052 : }
1053 4683 : }
1054 :
1055 872081 : void transform(const basegfx::B2DHomMatrix& rMatrix)
1056 : {
1057 872081 : mpBufferedData.reset();
1058 :
1059 872081 : if(mpControlVector)
1060 : {
1061 580613 : for(sal_uInt32 a(0); a < maPoints.count(); a++)
1062 : {
1063 509539 : basegfx::B2DPoint aCandidate = maPoints.getCoordinate(a);
1064 :
1065 509539 : if(mpControlVector->isUsed())
1066 : {
1067 509539 : const basegfx::B2DVector& rPrevVector(mpControlVector->getPrevVector(a));
1068 509539 : const basegfx::B2DVector& rNextVector(mpControlVector->getNextVector(a));
1069 :
1070 509539 : if(!rPrevVector.equalZero())
1071 : {
1072 313672 : basegfx::B2DVector aPrevVector(rMatrix * rPrevVector);
1073 313672 : mpControlVector->setPrevVector(a, aPrevVector);
1074 : }
1075 :
1076 509539 : if(!rNextVector.equalZero())
1077 : {
1078 313816 : basegfx::B2DVector aNextVector(rMatrix * rNextVector);
1079 313816 : mpControlVector->setNextVector(a, aNextVector);
1080 : }
1081 : }
1082 :
1083 509539 : aCandidate *= rMatrix;
1084 509539 : maPoints.setCoordinate(a, aCandidate);
1085 509539 : }
1086 :
1087 71074 : if(!mpControlVector->isUsed())
1088 0 : mpControlVector.reset();
1089 : }
1090 : else
1091 : {
1092 801007 : maPoints.transform(rMatrix);
1093 : }
1094 872081 : }
1095 : };
1096 :
1097 : namespace basegfx
1098 : {
1099 : namespace
1100 : {
1101 : struct DefaultPolygon: public rtl::Static<B2DPolygon::ImplType, DefaultPolygon> {};
1102 : }
1103 :
1104 5359855 : B2DPolygon::B2DPolygon()
1105 5359855 : : mpPolygon(DefaultPolygon::get())
1106 5359855 : {}
1107 :
1108 21997601 : B2DPolygon::B2DPolygon(const B2DPolygon& rPolygon)
1109 21997601 : : mpPolygon(rPolygon.mpPolygon)
1110 21997601 : {}
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 27346550 : B2DPolygon::~B2DPolygon()
1121 : {
1122 27346550 : }
1123 :
1124 84180 : B2DPolygon& B2DPolygon::operator=(const B2DPolygon& rPolygon)
1125 : {
1126 84180 : mpPolygon = rPolygon.mpPolygon;
1127 84180 : return *this;
1128 : }
1129 :
1130 60 : void B2DPolygon::makeUnique()
1131 : {
1132 60 : mpPolygon.make_unique();
1133 60 : }
1134 :
1135 49997 : bool B2DPolygon::operator==(const B2DPolygon& rPolygon) const
1136 : {
1137 49997 : if(mpPolygon.same_object(rPolygon.mpPolygon))
1138 2110 : return true;
1139 :
1140 47887 : return ((*mpPolygon) == (*rPolygon.mpPolygon));
1141 : }
1142 :
1143 6857 : bool B2DPolygon::operator!=(const B2DPolygon& rPolygon) const
1144 : {
1145 6857 : return !(*this == rPolygon);
1146 : }
1147 :
1148 13975238 : sal_uInt32 B2DPolygon::count() const
1149 : {
1150 13975238 : return mpPolygon->count();
1151 : }
1152 :
1153 131483070 : B2DPoint B2DPolygon::getB2DPoint(sal_uInt32 nIndex) const
1154 : {
1155 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1156 :
1157 131483070 : return mpPolygon->getPoint(nIndex);
1158 : }
1159 :
1160 11962797 : void B2DPolygon::setB2DPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1161 : {
1162 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1163 :
1164 11962797 : if(mpPolygon->getPoint(nIndex) != rValue)
1165 : {
1166 11594941 : mpPolygon->setPoint(nIndex, rValue);
1167 : }
1168 11962797 : }
1169 :
1170 60314 : void B2DPolygon::reserve(sal_uInt32 nCount)
1171 : {
1172 60314 : mpPolygon->reserve(nCount);
1173 60314 : }
1174 :
1175 496 : 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 496 : if(nCount)
1180 : {
1181 496 : mpPolygon->insert(nIndex, rPoint, nCount);
1182 : }
1183 496 : }
1184 :
1185 3385038 : void B2DPolygon::append(const B2DPoint& rPoint, sal_uInt32 nCount)
1186 : {
1187 3385038 : if(nCount)
1188 : {
1189 3385038 : mpPolygon->insert(mpPolygon->count(), rPoint, nCount);
1190 : }
1191 3385038 : }
1192 :
1193 11566278 : void B2DPolygon::append(const B2DPoint& rPoint)
1194 : {
1195 11566278 : mpPolygon->append(rPoint);
1196 11566278 : }
1197 :
1198 757189 : B2DPoint B2DPolygon::getPrevControlPoint(sal_uInt32 nIndex) const
1199 : {
1200 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1201 :
1202 757189 : if(mpPolygon->areControlPointsUsed())
1203 : {
1204 709471 : return mpPolygon->getPoint(nIndex) + mpPolygon->getPrevControlVector(nIndex);
1205 : }
1206 : else
1207 : {
1208 47718 : return mpPolygon->getPoint(nIndex);
1209 : }
1210 : }
1211 :
1212 751472 : B2DPoint B2DPolygon::getNextControlPoint(sal_uInt32 nIndex) const
1213 : {
1214 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1215 :
1216 751472 : if(mpPolygon->areControlPointsUsed())
1217 : {
1218 703778 : return mpPolygon->getPoint(nIndex) + mpPolygon->getNextControlVector(nIndex);
1219 : }
1220 : else
1221 : {
1222 47694 : return mpPolygon->getPoint(nIndex);
1223 : }
1224 : }
1225 :
1226 17634 : void B2DPolygon::setPrevControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1227 : {
1228 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1229 17634 : const basegfx::B2DVector aNewVector(rValue - mpPolygon->getPoint(nIndex));
1230 :
1231 17634 : if(mpPolygon->getPrevControlVector(nIndex) != aNewVector)
1232 : {
1233 11857 : mpPolygon->setPrevControlVector(nIndex, aNewVector);
1234 17634 : }
1235 17634 : }
1236 :
1237 12989 : void B2DPolygon::setNextControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1238 : {
1239 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1240 12989 : const basegfx::B2DVector aNewVector(rValue - mpPolygon->getPoint(nIndex));
1241 :
1242 12989 : if(mpPolygon->getNextControlVector(nIndex) != aNewVector)
1243 : {
1244 7211 : mpPolygon->setNextControlVector(nIndex, aNewVector);
1245 12989 : }
1246 12989 : }
1247 :
1248 2 : 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 2 : const B2DPoint aPoint(mpPolygon->getPoint(nIndex));
1252 4 : const basegfx::B2DVector aNewPrev(rPrev - aPoint);
1253 4 : const basegfx::B2DVector aNewNext(rNext - aPoint);
1254 :
1255 2 : if(mpPolygon->getPrevControlVector(nIndex) != aNewPrev || mpPolygon->getNextControlVector(nIndex) != aNewNext)
1256 : {
1257 2 : mpPolygon->setControlVectors(nIndex, aNewPrev, aNewNext);
1258 2 : }
1259 2 : }
1260 :
1261 20 : void B2DPolygon::resetPrevControlPoint(sal_uInt32 nIndex)
1262 : {
1263 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1264 :
1265 20 : if(mpPolygon->areControlPointsUsed() && !mpPolygon->getPrevControlVector(nIndex).equalZero())
1266 : {
1267 20 : mpPolygon->setPrevControlVector(nIndex, B2DVector::getEmptyVector());
1268 : }
1269 20 : }
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 2 : void B2DPolygon::resetControlPoints()
1282 : {
1283 2 : if(mpPolygon->areControlPointsUsed())
1284 : {
1285 2 : mpPolygon->resetControlVectors();
1286 : }
1287 2 : }
1288 :
1289 125391 : void B2DPolygon::appendBezierSegment(
1290 : const B2DPoint& rNextControlPoint,
1291 : const B2DPoint& rPrevControlPoint,
1292 : const B2DPoint& rPoint)
1293 : {
1294 125391 : const B2DVector aNewNextVector(mpPolygon->count() ? B2DVector(rNextControlPoint - mpPolygon->getPoint(mpPolygon->count() - 1)) : B2DVector::getEmptyVector());
1295 250782 : const B2DVector aNewPrevVector(rPrevControlPoint - rPoint);
1296 :
1297 125391 : if(aNewNextVector.equalZero() && aNewPrevVector.equalZero())
1298 : {
1299 1509 : mpPolygon->insert(mpPolygon->count(), rPoint, 1);
1300 : }
1301 : else
1302 : {
1303 123882 : mpPolygon->appendBezierSegment(aNewNextVector, aNewPrevVector, rPoint);
1304 125391 : }
1305 125391 : }
1306 :
1307 12444506 : bool B2DPolygon::areControlPointsUsed() const
1308 : {
1309 12444506 : return mpPolygon->areControlPointsUsed();
1310 : }
1311 :
1312 23930 : bool B2DPolygon::isPrevControlPointUsed(sal_uInt32 nIndex) const
1313 : {
1314 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1315 :
1316 23930 : return (mpPolygon->areControlPointsUsed() && !mpPolygon->getPrevControlVector(nIndex).equalZero());
1317 : }
1318 :
1319 11296 : bool B2DPolygon::isNextControlPointUsed(sal_uInt32 nIndex) const
1320 : {
1321 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1322 :
1323 11296 : return (mpPolygon->areControlPointsUsed() && !mpPolygon->getNextControlVector(nIndex).equalZero());
1324 : }
1325 :
1326 140622 : B2VectorContinuity B2DPolygon::getContinuityInPoint(sal_uInt32 nIndex) const
1327 : {
1328 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1329 :
1330 140622 : if(mpPolygon->areControlPointsUsed())
1331 : {
1332 140622 : const B2DVector& rPrev(mpPolygon->getPrevControlVector(nIndex));
1333 140622 : const B2DVector& rNext(mpPolygon->getNextControlVector(nIndex));
1334 :
1335 140622 : return getContinuity(rPrev, rNext);
1336 : }
1337 : else
1338 : {
1339 0 : return CONTINUITY_NONE;
1340 : }
1341 : }
1342 :
1343 785173 : void B2DPolygon::getBezierSegment(sal_uInt32 nIndex, B2DCubicBezier& rTarget) const
1344 : {
1345 : OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1346 785173 : const bool bNextIndexValidWithoutClose(nIndex + 1 < mpPolygon->count());
1347 :
1348 785173 : if(bNextIndexValidWithoutClose || mpPolygon->isClosed())
1349 : {
1350 784803 : const sal_uInt32 nNextIndex(bNextIndexValidWithoutClose ? nIndex + 1 : 0);
1351 784803 : rTarget.setStartPoint(mpPolygon->getPoint(nIndex));
1352 784803 : rTarget.setEndPoint(mpPolygon->getPoint(nNextIndex));
1353 :
1354 784803 : if(mpPolygon->areControlPointsUsed())
1355 : {
1356 707104 : rTarget.setControlPointA(rTarget.getStartPoint() + mpPolygon->getNextControlVector(nIndex));
1357 707104 : rTarget.setControlPointB(rTarget.getEndPoint() + mpPolygon->getPrevControlVector(nNextIndex));
1358 : }
1359 : else
1360 : {
1361 : // no bezier, reset control poins at rTarget
1362 77699 : rTarget.setControlPointA(rTarget.getStartPoint());
1363 77699 : rTarget.setControlPointB(rTarget.getEndPoint());
1364 : }
1365 : }
1366 : else
1367 : {
1368 : // no valid edge at all, reset rTarget to current point
1369 370 : const B2DPoint aPoint(mpPolygon->getPoint(nIndex));
1370 370 : rTarget.setStartPoint(aPoint);
1371 370 : rTarget.setEndPoint(aPoint);
1372 370 : rTarget.setControlPointA(aPoint);
1373 370 : rTarget.setControlPointB(aPoint);
1374 : }
1375 785173 : }
1376 :
1377 5471 : B2DPolygon B2DPolygon::getDefaultAdaptiveSubdivision() const
1378 : {
1379 5471 : return mpPolygon->getDefaultAdaptiveSubdivision(*this);
1380 : }
1381 :
1382 5579166 : B2DRange B2DPolygon::getB2DRange() const
1383 : {
1384 5579166 : return mpPolygon->getB2DRange(*this);
1385 : }
1386 :
1387 4966 : void B2DPolygon::append(const B2DPolygon& rPoly, sal_uInt32 nIndex, sal_uInt32 nCount)
1388 : {
1389 4966 : if(rPoly.count())
1390 : {
1391 4934 : if(!nCount)
1392 : {
1393 4934 : nCount = rPoly.count();
1394 : }
1395 :
1396 4934 : if(0 == nIndex && nCount == rPoly.count())
1397 : {
1398 4934 : 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 4966 : }
1408 :
1409 55860 : void B2DPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
1410 : {
1411 : OSL_ENSURE(nIndex + nCount <= mpPolygon->count(), "B2DPolygon Remove outside range (!)");
1412 :
1413 55860 : if(nCount)
1414 : {
1415 55860 : mpPolygon->remove(nIndex, nCount);
1416 : }
1417 55860 : }
1418 :
1419 147333 : void B2DPolygon::clear()
1420 : {
1421 147333 : mpPolygon = DefaultPolygon::get();
1422 147333 : }
1423 :
1424 6255591 : bool B2DPolygon::isClosed() const
1425 : {
1426 6255591 : return mpPolygon->isClosed();
1427 : }
1428 :
1429 5160261 : void B2DPolygon::setClosed(bool bNew)
1430 : {
1431 5160261 : if(isClosed() != bNew)
1432 : {
1433 4916775 : mpPolygon->setClosed(bNew);
1434 : }
1435 5160261 : }
1436 :
1437 765 : void B2DPolygon::flip()
1438 : {
1439 765 : if(count() > 1)
1440 : {
1441 765 : mpPolygon->flip();
1442 : }
1443 765 : }
1444 :
1445 32973 : bool B2DPolygon::hasDoublePoints() const
1446 : {
1447 32973 : return (mpPolygon->count() > 1 && mpPolygon->hasDoublePoints());
1448 : }
1449 :
1450 28122 : void B2DPolygon::removeDoublePoints()
1451 : {
1452 28122 : if(hasDoublePoints())
1453 : {
1454 4683 : mpPolygon->removeDoublePointsAtBeginEnd();
1455 4683 : mpPolygon->removeDoublePointsWholeTrack();
1456 : }
1457 28122 : }
1458 :
1459 899752 : void B2DPolygon::transform(const B2DHomMatrix& rMatrix)
1460 : {
1461 899752 : if(mpPolygon->count() && !rMatrix.isIdentity())
1462 : {
1463 872081 : mpPolygon->transform(rMatrix);
1464 : }
1465 899752 : }
1466 :
1467 : } // end of namespace basegfx
1468 :
1469 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|