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