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