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