1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <osl/diagnose.h>
21 #include <basegfx/polygon/b2dpolygon.hxx>
22 #include <basegfx/point/b2dpoint.hxx>
23 #include <basegfx/vector/b2dvector.hxx>
24 #include <basegfx/matrix/b2dhommatrix.hxx>
25 #include <basegfx/curve/b2dcubicbezier.hxx>
26 #include <rtl/instance.hxx>
27 #include <basegfx/polygon/b2dpolygontools.hxx>
28 #include <boost/scoped_ptr.hpp>
32 //////////////////////////////////////////////////////////////////////////////
34 struct CoordinateData2D
: public basegfx::B2DPoint
39 explicit CoordinateData2D(const basegfx::B2DPoint
& rData
)
43 CoordinateData2D
& operator=(const basegfx::B2DPoint
& rData
)
45 B2DPoint::operator=(rData
);
49 void transform(const basegfx::B2DHomMatrix
& rMatrix
)
55 //////////////////////////////////////////////////////////////////////////////
57 class CoordinateDataArray2D
59 typedef ::std::vector
< CoordinateData2D
> CoordinateData2DVector
;
61 CoordinateData2DVector maVector
;
64 explicit CoordinateDataArray2D(sal_uInt32 nCount
)
69 explicit CoordinateDataArray2D(const CoordinateDataArray2D
& rOriginal
)
70 : maVector(rOriginal
.maVector
)
74 CoordinateDataArray2D(const CoordinateDataArray2D
& rOriginal
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
75 : maVector(rOriginal
.maVector
.begin() + nIndex
, rOriginal
.maVector
.begin() + (nIndex
+ nCount
))
79 sal_uInt32
count() const
81 return maVector
.size();
84 bool operator==(const CoordinateDataArray2D
& rCandidate
) const
86 return (maVector
== rCandidate
.maVector
);
89 const basegfx::B2DPoint
& getCoordinate(sal_uInt32 nIndex
) const
91 return maVector
[nIndex
];
94 void setCoordinate(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rValue
)
96 maVector
[nIndex
] = rValue
;
99 void reserve(sal_uInt32 nCount
)
101 maVector
.reserve(nCount
);
104 void append(const CoordinateData2D
& rValue
)
106 maVector
.push_back(rValue
);
109 void insert(sal_uInt32 nIndex
, const CoordinateData2D
& rValue
, sal_uInt32 nCount
)
113 // add nCount copies of rValue
114 CoordinateData2DVector::iterator
aIndex(maVector
.begin());
116 maVector
.insert(aIndex
, nCount
, rValue
);
120 void insert(sal_uInt32 nIndex
, const CoordinateDataArray2D
& rSource
)
122 const sal_uInt32
nCount(rSource
.maVector
.size());
127 CoordinateData2DVector::iterator
aIndex(maVector
.begin());
129 CoordinateData2DVector::const_iterator
aStart(rSource
.maVector
.begin());
130 CoordinateData2DVector::const_iterator
aEnd(rSource
.maVector
.end());
131 maVector
.insert(aIndex
, aStart
, aEnd
);
135 void remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
140 CoordinateData2DVector::iterator
aStart(maVector
.begin());
142 const CoordinateData2DVector::iterator
aEnd(aStart
+ nCount
);
143 maVector
.erase(aStart
, aEnd
);
147 void flip(bool bIsClosed
)
149 if(maVector
.size() > 1)
151 // to keep the same point at index 0, just flip all points except the
152 // first one when closed
153 const sal_uInt32
nHalfSize(bIsClosed
? (maVector
.size() - 1) >> 1 : maVector
.size() >> 1);
154 CoordinateData2DVector::iterator
aStart(bIsClosed
? maVector
.begin() + 1 : maVector
.begin());
155 CoordinateData2DVector::iterator
aEnd(maVector
.end() - 1);
157 for(sal_uInt32
a(0); a
< nHalfSize
; a
++)
159 ::std::swap(*aStart
, *aEnd
);
166 void removeDoublePointsAtBeginEnd()
168 // remove from end as long as there are at least two points
169 // and begin/end are equal
170 while((maVector
.size() > 1) && (maVector
[0] == maVector
[maVector
.size() - 1]))
176 void removeDoublePointsWholeTrack()
178 sal_uInt32
nIndex(0);
180 // test as long as there are at least two points and as long as the index
181 // is smaller or equal second last point
182 while((maVector
.size() > 1) && (nIndex
<= maVector
.size() - 2))
184 if(maVector
[nIndex
] == maVector
[nIndex
+ 1])
186 // if next is same as index, delete next
187 maVector
.erase(maVector
.begin() + (nIndex
+ 1));
191 // if different, step forward
197 void transform(const basegfx::B2DHomMatrix
& rMatrix
)
199 CoordinateData2DVector::iterator
aStart(maVector
.begin());
200 CoordinateData2DVector::iterator
aEnd(maVector
.end());
202 for(; aStart
!= aEnd
; ++aStart
)
204 aStart
->transform(rMatrix
);
208 const basegfx::B2DPoint
* begin() const
213 return &maVector
.front();
216 const basegfx::B2DPoint
* end() const
221 return (&maVector
.back())+1;
224 basegfx::B2DPoint
* begin()
229 return &maVector
.front();
232 basegfx::B2DPoint
* end()
237 return (&maVector
.back())+1;
241 //////////////////////////////////////////////////////////////////////////////
243 class ControlVectorPair2D
245 basegfx::B2DVector maPrevVector
;
246 basegfx::B2DVector maNextVector
;
249 explicit ControlVectorPair2D() {}
251 const basegfx::B2DVector
& getPrevVector() const
256 void setPrevVector(const basegfx::B2DVector
& rValue
)
258 if(rValue
!= maPrevVector
)
259 maPrevVector
= rValue
;
262 const basegfx::B2DVector
& getNextVector() const
267 void setNextVector(const basegfx::B2DVector
& rValue
)
269 if(rValue
!= maNextVector
)
270 maNextVector
= rValue
;
273 bool operator==(const ControlVectorPair2D
& rData
) const
275 return (maPrevVector
== rData
.getPrevVector() && maNextVector
== rData
.getNextVector());
280 ::std::swap(maPrevVector
, maNextVector
);
284 //////////////////////////////////////////////////////////////////////////////
286 class ControlVectorArray2D
288 typedef ::std::vector
< ControlVectorPair2D
> ControlVectorPair2DVector
;
290 ControlVectorPair2DVector maVector
;
291 sal_uInt32 mnUsedVectors
;
294 explicit ControlVectorArray2D(sal_uInt32 nCount
)
299 ControlVectorArray2D(const ControlVectorArray2D
& rOriginal
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
303 ControlVectorPair2DVector::const_iterator
aStart(rOriginal
.maVector
.begin());
305 ControlVectorPair2DVector::const_iterator
aEnd(aStart
);
307 maVector
.reserve(nCount
);
309 for(; aStart
!= aEnd
; ++aStart
)
311 if(!aStart
->getPrevVector().equalZero())
314 if(!aStart
->getNextVector().equalZero())
317 maVector
.push_back(*aStart
);
321 sal_uInt32
count() const
323 return maVector
.size();
326 bool operator==(const ControlVectorArray2D
& rCandidate
) const
328 return (maVector
== rCandidate
.maVector
);
333 return (0 != mnUsedVectors
);
336 const basegfx::B2DVector
& getPrevVector(sal_uInt32 nIndex
) const
338 return maVector
[nIndex
].getPrevVector();
341 void setPrevVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
343 bool bWasUsed(mnUsedVectors
&& !maVector
[nIndex
].getPrevVector().equalZero());
344 bool bIsUsed(!rValue
.equalZero());
350 maVector
[nIndex
].setPrevVector(rValue
);
354 maVector
[nIndex
].setPrevVector(basegfx::B2DVector::getEmptyVector());
362 maVector
[nIndex
].setPrevVector(rValue
);
368 const basegfx::B2DVector
& getNextVector(sal_uInt32 nIndex
) const
370 return maVector
[nIndex
].getNextVector();
373 void setNextVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
375 bool bWasUsed(mnUsedVectors
&& !maVector
[nIndex
].getNextVector().equalZero());
376 bool bIsUsed(!rValue
.equalZero());
382 maVector
[nIndex
].setNextVector(rValue
);
386 maVector
[nIndex
].setNextVector(basegfx::B2DVector::getEmptyVector());
394 maVector
[nIndex
].setNextVector(rValue
);
400 void append(const ControlVectorPair2D
& rValue
)
402 maVector
.push_back(rValue
);
404 if(!rValue
.getPrevVector().equalZero())
407 if(!rValue
.getNextVector().equalZero())
411 void insert(sal_uInt32 nIndex
, const ControlVectorPair2D
& rValue
, sal_uInt32 nCount
)
415 // add nCount copies of rValue
416 ControlVectorPair2DVector::iterator
aIndex(maVector
.begin());
418 maVector
.insert(aIndex
, nCount
, rValue
);
420 if(!rValue
.getPrevVector().equalZero())
421 mnUsedVectors
+= nCount
;
423 if(!rValue
.getNextVector().equalZero())
424 mnUsedVectors
+= nCount
;
428 void insert(sal_uInt32 nIndex
, const ControlVectorArray2D
& rSource
)
430 const sal_uInt32
nCount(rSource
.maVector
.size());
435 ControlVectorPair2DVector::iterator
aIndex(maVector
.begin());
437 ControlVectorPair2DVector::const_iterator
aStart(rSource
.maVector
.begin());
438 ControlVectorPair2DVector::const_iterator
aEnd(rSource
.maVector
.end());
439 maVector
.insert(aIndex
, aStart
, aEnd
);
441 for(; aStart
!= aEnd
; ++aStart
)
443 if(!aStart
->getPrevVector().equalZero())
446 if(!aStart
->getNextVector().equalZero())
452 void remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
456 const ControlVectorPair2DVector::iterator
aDeleteStart(maVector
.begin() + nIndex
);
457 const ControlVectorPair2DVector::iterator
aDeleteEnd(aDeleteStart
+ nCount
);
458 ControlVectorPair2DVector::const_iterator
aStart(aDeleteStart
);
460 for(; mnUsedVectors
&& aStart
!= aDeleteEnd
; ++aStart
)
462 if(!aStart
->getPrevVector().equalZero())
465 if(mnUsedVectors
&& !aStart
->getNextVector().equalZero())
470 maVector
.erase(aDeleteStart
, aDeleteEnd
);
474 void flip(bool bIsClosed
)
476 if(maVector
.size() > 1)
478 // to keep the same point at index 0, just flip all points except the
479 // first one when closed
480 const sal_uInt32
nHalfSize(bIsClosed
? (maVector
.size() - 1) >> 1 : maVector
.size() >> 1);
481 ControlVectorPair2DVector::iterator
aStart(bIsClosed
? maVector
.begin() + 1 : maVector
.begin());
482 ControlVectorPair2DVector::iterator
aEnd(maVector
.end() - 1);
484 for(sal_uInt32
a(0); a
< nHalfSize
; a
++)
486 // swap Prev and Next
491 ::std::swap(*aStart
, *aEnd
);
499 // swap Prev and Next at middle element (if exists)
505 // swap Prev and Next at start element
506 maVector
.begin()->flip();
512 //////////////////////////////////////////////////////////////////////////////
514 class ImplBufferedData
517 // Possibility to hold the last subdivision
518 boost::scoped_ptr
< basegfx::B2DPolygon
> mpDefaultSubdivision
;
520 // Possibility to hold the last B2DRange calculation
521 boost::scoped_ptr
< basegfx::B2DRange
> mpB2DRange
;
525 : mpDefaultSubdivision(),
529 const basegfx::B2DPolygon
& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon
& rSource
) const
531 if(!mpDefaultSubdivision
)
533 const_cast< ImplBufferedData
* >(this)->mpDefaultSubdivision
.reset(new basegfx::B2DPolygon(basegfx::tools::adaptiveSubdivideByCount(rSource
, 9)));
536 return *mpDefaultSubdivision
;
539 const basegfx::B2DRange
& getB2DRange(const basegfx::B2DPolygon
& rSource
) const
543 basegfx::B2DRange aNewRange
;
544 const sal_uInt32
nPointCount(rSource
.count());
548 for(sal_uInt32
a(0); a
< nPointCount
; a
++)
550 aNewRange
.expand(rSource
.getB2DPoint(a
));
553 if(rSource
.areControlPointsUsed())
555 const sal_uInt32
nEdgeCount(rSource
.isClosed() ? nPointCount
: nPointCount
- 1);
559 basegfx::B2DCubicBezier aEdge
;
560 aEdge
.setStartPoint(rSource
.getB2DPoint(0));
562 for(sal_uInt32
b(0); b
< nEdgeCount
; b
++)
564 const sal_uInt32
nNextIndex((b
+ 1) % nPointCount
);
565 aEdge
.setControlPointA(rSource
.getNextControlPoint(b
));
566 aEdge
.setControlPointB(rSource
.getPrevControlPoint(nNextIndex
));
567 aEdge
.setEndPoint(rSource
.getB2DPoint(nNextIndex
));
571 const basegfx::B2DRange
aBezierRangeWithControlPoints(aEdge
.getRange());
573 if(!aNewRange
.isInside(aBezierRangeWithControlPoints
))
575 // the range with control points of the current edge is not completely
576 // inside the current range without control points. Expand current range by
577 // subdividing the bezier segment.
578 // Ideal here is a subdivision at the extreme values, so use
579 // getAllExtremumPositions to get all extremas in one run
580 ::std::vector
< double > aExtremas
;
582 aExtremas
.reserve(4);
583 aEdge
.getAllExtremumPositions(aExtremas
);
585 const sal_uInt32
nExtremaCount(aExtremas
.size());
587 for(sal_uInt32
c(0); c
< nExtremaCount
; c
++)
589 aNewRange
.expand(aEdge
.interpolatePoint(aExtremas
[c
]));
595 aEdge
.setStartPoint(aEdge
.getEndPoint());
601 const_cast< ImplBufferedData
* >(this)->mpB2DRange
.reset(new basegfx::B2DRange(aNewRange
));
608 //////////////////////////////////////////////////////////////////////////////
613 // The point vector. This vector exists always and defines the
615 CoordinateDataArray2D maPoints
;
617 // The control point vectors. This vectors are created on demand
619 boost::scoped_ptr
< ControlVectorArray2D
> mpControlVector
;
621 // buffered data for e.g. default subdivision and range
622 boost::scoped_ptr
< ImplBufferedData
> mpBufferedData
;
624 // flag which decides if this polygon is opened or closed
628 const basegfx::B2DPolygon
& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon
& rSource
) const
630 if(!mpControlVector
|| !mpControlVector
->isUsed())
637 const_cast< ImplB2DPolygon
* >(this)->mpBufferedData
.reset(new ImplBufferedData
);
640 return mpBufferedData
->getDefaultAdaptiveSubdivision(rSource
);
643 const basegfx::B2DRange
& getB2DRange(const basegfx::B2DPolygon
& rSource
) const
647 const_cast< ImplB2DPolygon
* >(this)->mpBufferedData
.reset(new ImplBufferedData
);
650 return mpBufferedData
->getB2DRange(rSource
);
660 ImplB2DPolygon(const ImplB2DPolygon
& rToBeCopied
)
661 : maPoints(rToBeCopied
.maPoints
),
664 mbIsClosed(rToBeCopied
.mbIsClosed
)
666 // complete initialization using copy
667 if(rToBeCopied
.mpControlVector
&& rToBeCopied
.mpControlVector
->isUsed())
669 mpControlVector
.reset( new ControlVectorArray2D(*rToBeCopied
.mpControlVector
) );
673 ImplB2DPolygon(const ImplB2DPolygon
& rToBeCopied
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
674 : maPoints(rToBeCopied
.maPoints
, nIndex
, nCount
),
677 mbIsClosed(rToBeCopied
.mbIsClosed
)
679 // complete initialization using partly copy
680 if(rToBeCopied
.mpControlVector
&& rToBeCopied
.mpControlVector
->isUsed())
682 mpControlVector
.reset( new ControlVectorArray2D(*rToBeCopied
.mpControlVector
, nIndex
, nCount
) );
684 if(!mpControlVector
->isUsed())
685 mpControlVector
.reset();
689 ImplB2DPolygon
& operator=( const ImplB2DPolygon
& rToBeCopied
)
691 maPoints
= rToBeCopied
.maPoints
;
692 mpControlVector
.reset();
693 mpBufferedData
.reset();
694 mbIsClosed
= rToBeCopied
.mbIsClosed
;
696 // complete initialization using copy
697 if(rToBeCopied
.mpControlVector
&& rToBeCopied
.mpControlVector
->isUsed())
698 mpControlVector
.reset( new ControlVectorArray2D(*rToBeCopied
.mpControlVector
) );
703 sal_uInt32
count() const
705 return maPoints
.count();
708 bool isClosed() const
713 void setClosed(bool bNew
)
715 if(bNew
!= mbIsClosed
)
717 mpBufferedData
.reset();
722 bool operator==(const ImplB2DPolygon
& rCandidate
) const
724 if(mbIsClosed
== rCandidate
.mbIsClosed
)
726 if(maPoints
== rCandidate
.maPoints
)
728 bool bControlVectorsAreEqual(true);
732 if(rCandidate
.mpControlVector
)
734 bControlVectorsAreEqual
= ((*mpControlVector
) == (*rCandidate
.mpControlVector
));
738 // candidate has no control vector, so it's assumed all unused.
739 bControlVectorsAreEqual
= !mpControlVector
->isUsed();
744 if(rCandidate
.mpControlVector
)
746 // we have no control vector, so it's assumed all unused.
747 bControlVectorsAreEqual
= !rCandidate
.mpControlVector
->isUsed();
751 if(bControlVectorsAreEqual
)
761 const basegfx::B2DPoint
& getPoint(sal_uInt32 nIndex
) const
763 return maPoints
.getCoordinate(nIndex
);
766 void setPoint(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rValue
)
768 mpBufferedData
.reset();
769 maPoints
.setCoordinate(nIndex
, rValue
);
772 void reserve(sal_uInt32 nCount
)
774 maPoints
.reserve(nCount
);
777 void append(const basegfx::B2DPoint
& rPoint
)
779 mpBufferedData
.reset(); // TODO: is this needed?
780 const CoordinateData2D
aCoordinate(rPoint
);
781 maPoints
.append(aCoordinate
);
785 const ControlVectorPair2D aVectorPair
;
786 mpControlVector
->append(aVectorPair
);
790 void insert(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rPoint
, sal_uInt32 nCount
)
794 mpBufferedData
.reset();
795 CoordinateData2D
aCoordinate(rPoint
);
796 maPoints
.insert(nIndex
, aCoordinate
, nCount
);
800 ControlVectorPair2D aVectorPair
;
801 mpControlVector
->insert(nIndex
, aVectorPair
, nCount
);
806 const basegfx::B2DVector
& getPrevControlVector(sal_uInt32 nIndex
) const
810 return mpControlVector
->getPrevVector(nIndex
);
814 return basegfx::B2DVector::getEmptyVector();
818 void setPrevControlVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
822 if(!rValue
.equalZero())
824 mpBufferedData
.reset();
825 mpControlVector
.reset( new ControlVectorArray2D(maPoints
.count()) );
826 mpControlVector
->setPrevVector(nIndex
, rValue
);
831 mpBufferedData
.reset();
832 mpControlVector
->setPrevVector(nIndex
, rValue
);
834 if(!mpControlVector
->isUsed())
835 mpControlVector
.reset();
839 const basegfx::B2DVector
& getNextControlVector(sal_uInt32 nIndex
) const
843 return mpControlVector
->getNextVector(nIndex
);
847 return basegfx::B2DVector::getEmptyVector();
851 void setNextControlVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
855 if(!rValue
.equalZero())
857 mpBufferedData
.reset();
858 mpControlVector
.reset( new ControlVectorArray2D(maPoints
.count()) );
859 mpControlVector
->setNextVector(nIndex
, rValue
);
864 mpBufferedData
.reset();
865 mpControlVector
->setNextVector(nIndex
, rValue
);
867 if(!mpControlVector
->isUsed())
868 mpControlVector
.reset();
872 bool areControlPointsUsed() const
874 return (mpControlVector
&& mpControlVector
->isUsed());
877 void resetControlVectors(sal_uInt32 nIndex
)
879 setPrevControlVector(nIndex
, basegfx::B2DVector::getEmptyVector());
880 setNextControlVector(nIndex
, basegfx::B2DVector::getEmptyVector());
883 void resetControlVectors()
885 mpBufferedData
.reset();
886 mpControlVector
.reset();
889 void setControlVectors(sal_uInt32 nIndex
, const basegfx::B2DVector
& rPrev
, const basegfx::B2DVector
& rNext
)
891 setPrevControlVector(nIndex
, rPrev
);
892 setNextControlVector(nIndex
, rNext
);
895 void appendBezierSegment(const basegfx::B2DVector
& rNext
, const basegfx::B2DVector
& rPrev
, const basegfx::B2DPoint
& rPoint
)
897 mpBufferedData
.reset();
898 const sal_uInt32
nCount(maPoints
.count());
902 setNextControlVector(nCount
- 1, rNext
);
905 insert(nCount
, rPoint
, 1);
906 setPrevControlVector(nCount
, rPrev
);
909 void insert(sal_uInt32 nIndex
, const ImplB2DPolygon
& rSource
)
911 const sal_uInt32
nCount(rSource
.maPoints
.count());
915 mpBufferedData
.reset();
917 if(rSource
.mpControlVector
&& rSource
.mpControlVector
->isUsed() && !mpControlVector
)
919 mpControlVector
.reset( new ControlVectorArray2D(maPoints
.count()) );
922 maPoints
.insert(nIndex
, rSource
.maPoints
);
924 if(rSource
.mpControlVector
)
926 mpControlVector
->insert(nIndex
, *rSource
.mpControlVector
);
928 if(!mpControlVector
->isUsed())
929 mpControlVector
.reset();
931 else if(mpControlVector
)
933 ControlVectorPair2D aVectorPair
;
934 mpControlVector
->insert(nIndex
, aVectorPair
, nCount
);
939 void remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
943 mpBufferedData
.reset();
944 maPoints
.remove(nIndex
, nCount
);
948 mpControlVector
->remove(nIndex
, nCount
);
950 if(!mpControlVector
->isUsed())
951 mpControlVector
.reset();
958 if(maPoints
.count() > 1)
960 mpBufferedData
.reset();
963 maPoints
.flip(mbIsClosed
);
967 // flip control vector
968 mpControlVector
->flip(mbIsClosed
);
973 bool hasDoublePoints() const
977 // check for same start and end point
978 const sal_uInt32
nIndex(maPoints
.count() - 1);
980 if(maPoints
.getCoordinate(0) == maPoints
.getCoordinate(nIndex
))
984 if(mpControlVector
->getNextVector(nIndex
).equalZero() && mpControlVector
->getPrevVector(0).equalZero())
997 for(sal_uInt32
a(0); a
< maPoints
.count() - 1; a
++)
999 if(maPoints
.getCoordinate(a
) == maPoints
.getCoordinate(a
+ 1))
1003 if(mpControlVector
->getNextVector(a
).equalZero() && mpControlVector
->getPrevVector(a
+ 1).equalZero())
1018 void removeDoublePointsAtBeginEnd()
1020 // Only remove DoublePoints at Begin and End when poly is closed
1023 mpBufferedData
.reset();
1033 if(maPoints
.count() > 1)
1035 const sal_uInt32
nIndex(maPoints
.count() - 1);
1037 if(maPoints
.getCoordinate(0) == maPoints
.getCoordinate(nIndex
))
1041 if(mpControlVector
->getNextVector(nIndex
).equalZero() && mpControlVector
->getPrevVector(0).equalZero())
1055 const sal_uInt32
nIndex(maPoints
.count() - 1);
1057 if(mpControlVector
&& !mpControlVector
->getPrevVector(nIndex
).equalZero())
1059 mpControlVector
->setPrevVector(0, mpControlVector
->getPrevVector(nIndex
));
1069 maPoints
.removeDoublePointsAtBeginEnd();
1074 void removeDoublePointsWholeTrack()
1076 mpBufferedData
.reset();
1080 sal_uInt32
nIndex(0);
1082 // test as long as there are at least two points and as long as the index
1083 // is smaller or equal second last point
1084 while((maPoints
.count() > 1) && (nIndex
<= maPoints
.count() - 2))
1086 bool bRemove(maPoints
.getCoordinate(nIndex
) == maPoints
.getCoordinate(nIndex
+ 1));
1092 if(!mpControlVector
->getNextVector(nIndex
).equalZero() || !mpControlVector
->getPrevVector(nIndex
+ 1).equalZero())
1101 if(mpControlVector
&& !mpControlVector
->getPrevVector(nIndex
).equalZero())
1103 mpControlVector
->setPrevVector(nIndex
+ 1, mpControlVector
->getPrevVector(nIndex
));
1106 // if next is same as index and the control vectors are unused, delete index
1111 // if different, step forward
1118 maPoints
.removeDoublePointsWholeTrack();
1122 void transform(const basegfx::B2DHomMatrix
& rMatrix
)
1124 mpBufferedData
.reset();
1128 for(sal_uInt32
a(0); a
< maPoints
.count(); a
++)
1130 basegfx::B2DPoint aCandidate
= maPoints
.getCoordinate(a
);
1132 if(mpControlVector
->isUsed())
1134 const basegfx::B2DVector
& rPrevVector(mpControlVector
->getPrevVector(a
));
1135 const basegfx::B2DVector
& rNextVector(mpControlVector
->getNextVector(a
));
1137 if(!rPrevVector
.equalZero())
1139 basegfx::B2DVector
aPrevVector(rMatrix
* rPrevVector
);
1140 mpControlVector
->setPrevVector(a
, aPrevVector
);
1143 if(!rNextVector
.equalZero())
1145 basegfx::B2DVector
aNextVector(rMatrix
* rNextVector
);
1146 mpControlVector
->setNextVector(a
, aNextVector
);
1150 aCandidate
*= rMatrix
;
1151 maPoints
.setCoordinate(a
, aCandidate
);
1154 if(!mpControlVector
->isUsed())
1155 mpControlVector
.reset();
1159 maPoints
.transform(rMatrix
);
1163 const basegfx::B2DPoint
* begin() const
1165 return maPoints
.begin();
1168 const basegfx::B2DPoint
* end() const
1170 return maPoints
.end();
1173 basegfx::B2DPoint
* begin()
1175 mpBufferedData
.reset();
1176 return maPoints
.begin();
1179 basegfx::B2DPoint
* end()
1181 mpBufferedData
.reset();
1182 return maPoints
.end();
1186 //////////////////////////////////////////////////////////////////////////////
1192 struct DefaultPolygon
: public rtl::Static
<B2DPolygon::ImplType
, DefaultPolygon
> {};
1195 B2DPolygon::B2DPolygon()
1196 : mpPolygon(DefaultPolygon::get())
1199 B2DPolygon::B2DPolygon(const B2DPolygon
& rPolygon
)
1200 : mpPolygon(rPolygon
.mpPolygon
)
1203 B2DPolygon::B2DPolygon(const B2DPolygon
& rPolygon
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
1204 : mpPolygon(ImplB2DPolygon(*rPolygon
.mpPolygon
, nIndex
, nCount
))
1206 // TODO(P2): one extra temporary here (cow_wrapper copies
1207 // given ImplB2DPolygon into its internal impl_t wrapper type)
1208 OSL_ENSURE(nIndex
+ nCount
<= rPolygon
.mpPolygon
->count(), "B2DPolygon constructor outside range (!)");
1211 B2DPolygon::~B2DPolygon()
1215 B2DPolygon
& B2DPolygon::operator=(const B2DPolygon
& rPolygon
)
1217 mpPolygon
= rPolygon
.mpPolygon
;
1221 void B2DPolygon::makeUnique()
1223 mpPolygon
.make_unique();
1226 bool B2DPolygon::operator==(const B2DPolygon
& rPolygon
) const
1228 if(mpPolygon
.same_object(rPolygon
.mpPolygon
))
1231 return ((*mpPolygon
) == (*rPolygon
.mpPolygon
));
1234 bool B2DPolygon::operator!=(const B2DPolygon
& rPolygon
) const
1236 return !(*this == rPolygon
);
1239 sal_uInt32
B2DPolygon::count() const
1241 return mpPolygon
->count();
1244 B2DPoint
B2DPolygon::getB2DPoint(sal_uInt32 nIndex
) const
1246 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1248 return mpPolygon
->getPoint(nIndex
);
1251 void B2DPolygon::setB2DPoint(sal_uInt32 nIndex
, const B2DPoint
& rValue
)
1253 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1255 if(mpPolygon
->getPoint(nIndex
) != rValue
)
1257 mpPolygon
->setPoint(nIndex
, rValue
);
1261 void B2DPolygon::reserve(sal_uInt32 nCount
)
1263 mpPolygon
->reserve(nCount
);
1266 void B2DPolygon::insert(sal_uInt32 nIndex
, const B2DPoint
& rPoint
, sal_uInt32 nCount
)
1268 OSL_ENSURE(nIndex
<= mpPolygon
->count(), "B2DPolygon Insert outside range (!)");
1272 mpPolygon
->insert(nIndex
, rPoint
, nCount
);
1276 void B2DPolygon::append(const B2DPoint
& rPoint
, sal_uInt32 nCount
)
1280 mpPolygon
->insert(mpPolygon
->count(), rPoint
, nCount
);
1284 void B2DPolygon::append(const B2DPoint
& rPoint
)
1286 mpPolygon
->append(rPoint
);
1289 B2DPoint
B2DPolygon::getPrevControlPoint(sal_uInt32 nIndex
) const
1291 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1293 if(mpPolygon
->areControlPointsUsed())
1295 return mpPolygon
->getPoint(nIndex
) + mpPolygon
->getPrevControlVector(nIndex
);
1299 return mpPolygon
->getPoint(nIndex
);
1303 B2DPoint
B2DPolygon::getNextControlPoint(sal_uInt32 nIndex
) const
1305 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1307 if(mpPolygon
->areControlPointsUsed())
1309 return mpPolygon
->getPoint(nIndex
) + mpPolygon
->getNextControlVector(nIndex
);
1313 return mpPolygon
->getPoint(nIndex
);
1317 void B2DPolygon::setPrevControlPoint(sal_uInt32 nIndex
, const B2DPoint
& rValue
)
1319 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1320 const basegfx::B2DVector
aNewVector(rValue
- mpPolygon
->getPoint(nIndex
));
1322 if(mpPolygon
->getPrevControlVector(nIndex
) != aNewVector
)
1324 mpPolygon
->setPrevControlVector(nIndex
, aNewVector
);
1328 void B2DPolygon::setNextControlPoint(sal_uInt32 nIndex
, const B2DPoint
& rValue
)
1330 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1331 const basegfx::B2DVector
aNewVector(rValue
- mpPolygon
->getPoint(nIndex
));
1333 if(mpPolygon
->getNextControlVector(nIndex
) != aNewVector
)
1335 mpPolygon
->setNextControlVector(nIndex
, aNewVector
);
1339 void B2DPolygon::setControlPoints(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rPrev
, const basegfx::B2DPoint
& rNext
)
1341 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1342 const B2DPoint
aPoint(mpPolygon
->getPoint(nIndex
));
1343 const basegfx::B2DVector
aNewPrev(rPrev
- aPoint
);
1344 const basegfx::B2DVector
aNewNext(rNext
- aPoint
);
1346 if(mpPolygon
->getPrevControlVector(nIndex
) != aNewPrev
|| mpPolygon
->getNextControlVector(nIndex
) != aNewNext
)
1348 mpPolygon
->setControlVectors(nIndex
, aNewPrev
, aNewNext
);
1352 void B2DPolygon::resetPrevControlPoint(sal_uInt32 nIndex
)
1354 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1356 if(mpPolygon
->areControlPointsUsed() && !mpPolygon
->getPrevControlVector(nIndex
).equalZero())
1358 mpPolygon
->setPrevControlVector(nIndex
, B2DVector::getEmptyVector());
1362 void B2DPolygon::resetNextControlPoint(sal_uInt32 nIndex
)
1364 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1366 if(mpPolygon
->areControlPointsUsed() && !mpPolygon
->getNextControlVector(nIndex
).equalZero())
1368 mpPolygon
->setNextControlVector(nIndex
, B2DVector::getEmptyVector());
1372 void B2DPolygon::resetControlPoints()
1374 if(mpPolygon
->areControlPointsUsed())
1376 mpPolygon
->resetControlVectors();
1380 void B2DPolygon::appendBezierSegment(
1381 const B2DPoint
& rNextControlPoint
,
1382 const B2DPoint
& rPrevControlPoint
,
1383 const B2DPoint
& rPoint
)
1385 const B2DVector
aNewNextVector(mpPolygon
->count() ? B2DVector(rNextControlPoint
- mpPolygon
->getPoint(mpPolygon
->count() - 1)) : B2DVector::getEmptyVector());
1386 const B2DVector
aNewPrevVector(rPrevControlPoint
- rPoint
);
1388 if(aNewNextVector
.equalZero() && aNewPrevVector
.equalZero())
1390 mpPolygon
->insert(mpPolygon
->count(), rPoint
, 1);
1394 mpPolygon
->appendBezierSegment(aNewNextVector
, aNewPrevVector
, rPoint
);
1398 bool B2DPolygon::areControlPointsUsed() const
1400 return mpPolygon
->areControlPointsUsed();
1403 bool B2DPolygon::isPrevControlPointUsed(sal_uInt32 nIndex
) const
1405 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1407 return (mpPolygon
->areControlPointsUsed() && !mpPolygon
->getPrevControlVector(nIndex
).equalZero());
1410 bool B2DPolygon::isNextControlPointUsed(sal_uInt32 nIndex
) const
1412 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1414 return (mpPolygon
->areControlPointsUsed() && !mpPolygon
->getNextControlVector(nIndex
).equalZero());
1417 B2VectorContinuity
B2DPolygon::getContinuityInPoint(sal_uInt32 nIndex
) const
1419 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1421 if(mpPolygon
->areControlPointsUsed())
1423 const B2DVector
& rPrev(mpPolygon
->getPrevControlVector(nIndex
));
1424 const B2DVector
& rNext(mpPolygon
->getNextControlVector(nIndex
));
1426 return getContinuity(rPrev
, rNext
);
1430 return CONTINUITY_NONE
;
1434 void B2DPolygon::getBezierSegment(sal_uInt32 nIndex
, B2DCubicBezier
& rTarget
) const
1436 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1437 const bool bNextIndexValidWithoutClose(nIndex
+ 1 < mpPolygon
->count());
1439 if(bNextIndexValidWithoutClose
|| mpPolygon
->isClosed())
1441 const sal_uInt32
nNextIndex(bNextIndexValidWithoutClose
? nIndex
+ 1 : 0);
1442 rTarget
.setStartPoint(mpPolygon
->getPoint(nIndex
));
1443 rTarget
.setEndPoint(mpPolygon
->getPoint(nNextIndex
));
1445 if(mpPolygon
->areControlPointsUsed())
1447 rTarget
.setControlPointA(rTarget
.getStartPoint() + mpPolygon
->getNextControlVector(nIndex
));
1448 rTarget
.setControlPointB(rTarget
.getEndPoint() + mpPolygon
->getPrevControlVector(nNextIndex
));
1452 // no bezier, reset control poins at rTarget
1453 rTarget
.setControlPointA(rTarget
.getStartPoint());
1454 rTarget
.setControlPointB(rTarget
.getEndPoint());
1459 // no valid edge at all, reset rTarget to current point
1460 const B2DPoint
aPoint(mpPolygon
->getPoint(nIndex
));
1461 rTarget
.setStartPoint(aPoint
);
1462 rTarget
.setEndPoint(aPoint
);
1463 rTarget
.setControlPointA(aPoint
);
1464 rTarget
.setControlPointB(aPoint
);
1468 B2DPolygon
B2DPolygon::getDefaultAdaptiveSubdivision() const
1470 return mpPolygon
->getDefaultAdaptiveSubdivision(*this);
1473 B2DRange
B2DPolygon::getB2DRange() const
1475 return mpPolygon
->getB2DRange(*this);
1478 void B2DPolygon::append(const B2DPolygon
& rPoly
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
1484 nCount
= rPoly
.count();
1487 if(0 == nIndex
&& nCount
== rPoly
.count())
1489 mpPolygon
->insert(mpPolygon
->count(), *rPoly
.mpPolygon
);
1493 OSL_ENSURE(nIndex
+ nCount
<= rPoly
.mpPolygon
->count(), "B2DPolygon Append outside range (!)");
1494 ImplB2DPolygon
aTempPoly(*rPoly
.mpPolygon
, nIndex
, nCount
);
1495 mpPolygon
->insert(mpPolygon
->count(), aTempPoly
);
1500 void B2DPolygon::remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
1502 OSL_ENSURE(nIndex
+ nCount
<= mpPolygon
->count(), "B2DPolygon Remove outside range (!)");
1506 mpPolygon
->remove(nIndex
, nCount
);
1510 void B2DPolygon::clear()
1512 mpPolygon
= DefaultPolygon::get();
1515 bool B2DPolygon::isClosed() const
1517 return mpPolygon
->isClosed();
1520 void B2DPolygon::setClosed(bool bNew
)
1522 if(isClosed() != bNew
)
1524 mpPolygon
->setClosed(bNew
);
1528 void B2DPolygon::flip()
1536 bool B2DPolygon::hasDoublePoints() const
1538 return (mpPolygon
->count() > 1 && mpPolygon
->hasDoublePoints());
1541 void B2DPolygon::removeDoublePoints()
1543 if(hasDoublePoints())
1545 mpPolygon
->removeDoublePointsAtBeginEnd();
1546 mpPolygon
->removeDoublePointsWholeTrack();
1550 void B2DPolygon::transform(const B2DHomMatrix
& rMatrix
)
1552 if(mpPolygon
->count() && !rMatrix
.isIdentity())
1554 mpPolygon
->transform(rMatrix
);
1558 } // end of namespace basegfx
1560 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */