1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: b2dpolygon.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_basegfx.hxx"
33 #include <osl/diagnose.h>
34 #include <basegfx/polygon/b2dpolygon.hxx>
35 #include <basegfx/point/b2dpoint.hxx>
36 #include <basegfx/vector/b2dvector.hxx>
37 #include <basegfx/matrix/b2dhommatrix.hxx>
38 #include <basegfx/curve/b2dcubicbezier.hxx>
39 #include <rtl/instance.hxx>
40 #include <basegfx/polygon/b2dpolygontools.hxx>
41 #include <boost/scoped_ptr.hpp>
45 //////////////////////////////////////////////////////////////////////////////
47 class CoordinateData2D
49 basegfx::B2DPoint maPoint
;
56 explicit CoordinateData2D(const basegfx::B2DPoint
& rData
)
60 const basegfx::B2DPoint
& getCoordinate() const
65 void setCoordinate(const basegfx::B2DPoint
& rValue
)
71 bool operator==(const CoordinateData2D
& rData
) const
73 return (maPoint
== rData
.getCoordinate());
76 void transform(const basegfx::B2DHomMatrix
& rMatrix
)
82 //////////////////////////////////////////////////////////////////////////////
84 class CoordinateDataArray2D
86 typedef ::std::vector
< CoordinateData2D
> CoordinateData2DVector
;
88 CoordinateData2DVector maVector
;
91 explicit CoordinateDataArray2D(sal_uInt32 nCount
)
96 explicit CoordinateDataArray2D(const CoordinateDataArray2D
& rOriginal
)
97 : maVector(rOriginal
.maVector
)
101 CoordinateDataArray2D(const CoordinateDataArray2D
& rOriginal
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
102 : maVector(rOriginal
.maVector
.begin() + nIndex
, rOriginal
.maVector
.begin() + (nIndex
+ nCount
))
106 sal_uInt32
count() const
108 return maVector
.size();
111 bool operator==(const CoordinateDataArray2D
& rCandidate
) const
113 return (maVector
== rCandidate
.maVector
);
116 const basegfx::B2DPoint
& getCoordinate(sal_uInt32 nIndex
) const
118 return maVector
[nIndex
].getCoordinate();
121 void setCoordinate(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rValue
)
123 maVector
[nIndex
].setCoordinate(rValue
);
126 void insert(sal_uInt32 nIndex
, const CoordinateData2D
& rValue
, sal_uInt32 nCount
)
130 // add nCount copies of rValue
131 CoordinateData2DVector::iterator
aIndex(maVector
.begin());
133 maVector
.insert(aIndex
, nCount
, rValue
);
137 void insert(sal_uInt32 nIndex
, const CoordinateDataArray2D
& rSource
)
139 const sal_uInt32
nCount(rSource
.maVector
.size());
144 CoordinateData2DVector::iterator
aIndex(maVector
.begin());
146 CoordinateData2DVector::const_iterator
aStart(rSource
.maVector
.begin());
147 CoordinateData2DVector::const_iterator
aEnd(rSource
.maVector
.end());
148 maVector
.insert(aIndex
, aStart
, aEnd
);
152 void remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
157 CoordinateData2DVector::iterator
aStart(maVector
.begin());
159 const CoordinateData2DVector::iterator
aEnd(aStart
+ nCount
);
160 maVector
.erase(aStart
, aEnd
);
164 void flip(bool bIsClosed
)
166 if(maVector
.size() > 1)
168 // to keep the same point at index 0, just flip all points except the
169 // first one when closed
170 const sal_uInt32
nHalfSize(bIsClosed
? (maVector
.size() - 1) >> 1 : maVector
.size() >> 1);
171 CoordinateData2DVector::iterator
aStart(bIsClosed
? maVector
.begin() + 1 : maVector
.begin());
172 CoordinateData2DVector::iterator
aEnd(maVector
.end() - 1);
174 for(sal_uInt32
a(0); a
< nHalfSize
; a
++)
176 ::std::swap(*aStart
, *aEnd
);
183 void removeDoublePointsAtBeginEnd()
185 // remove from end as long as there are at least two points
186 // and begin/end are equal
187 while((maVector
.size() > 1) && (maVector
[0] == maVector
[maVector
.size() - 1]))
193 void removeDoublePointsWholeTrack()
195 sal_uInt32
nIndex(0);
197 // test as long as there are at least two points and as long as the index
198 // is smaller or equal second last point
199 while((maVector
.size() > 1) && (nIndex
<= maVector
.size() - 2))
201 if(maVector
[nIndex
] == maVector
[nIndex
+ 1])
203 // if next is same as index, delete next
204 maVector
.erase(maVector
.begin() + (nIndex
+ 1));
208 // if different, step forward
214 void transform(const basegfx::B2DHomMatrix
& rMatrix
)
216 CoordinateData2DVector::iterator
aStart(maVector
.begin());
217 CoordinateData2DVector::iterator
aEnd(maVector
.end());
219 for(; aStart
!= aEnd
; aStart
++)
221 aStart
->transform(rMatrix
);
226 //////////////////////////////////////////////////////////////////////////////
228 class ControlVectorPair2D
230 basegfx::B2DVector maPrevVector
;
231 basegfx::B2DVector maNextVector
;
234 const basegfx::B2DVector
& getPrevVector() const
239 void setPrevVector(const basegfx::B2DVector
& rValue
)
241 if(rValue
!= maPrevVector
)
242 maPrevVector
= rValue
;
245 const basegfx::B2DVector
& getNextVector() const
250 void setNextVector(const basegfx::B2DVector
& rValue
)
252 if(rValue
!= maNextVector
)
253 maNextVector
= rValue
;
256 bool operator==(const ControlVectorPair2D
& rData
) const
258 return (maPrevVector
== rData
.getPrevVector() && maNextVector
== rData
.getNextVector());
263 ::std::swap(maPrevVector
, maNextVector
);
267 //////////////////////////////////////////////////////////////////////////////
269 class ControlVectorArray2D
271 typedef ::std::vector
< ControlVectorPair2D
> ControlVectorPair2DVector
;
273 ControlVectorPair2DVector maVector
;
274 sal_uInt32 mnUsedVectors
;
277 explicit ControlVectorArray2D(sal_uInt32 nCount
)
282 ControlVectorArray2D(const ControlVectorArray2D
& rOriginal
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
286 ControlVectorPair2DVector::const_iterator
aStart(rOriginal
.maVector
.begin());
288 ControlVectorPair2DVector::const_iterator
aEnd(aStart
);
290 maVector
.reserve(nCount
);
292 for(; aStart
!= aEnd
; aStart
++)
294 if(!aStart
->getPrevVector().equalZero())
297 if(!aStart
->getNextVector().equalZero())
300 maVector
.push_back(*aStart
);
304 sal_uInt32
count() const
306 return maVector
.size();
309 bool operator==(const ControlVectorArray2D
& rCandidate
) const
311 return (maVector
== rCandidate
.maVector
);
316 return (0 != mnUsedVectors
);
319 const basegfx::B2DVector
& getPrevVector(sal_uInt32 nIndex
) const
321 return maVector
[nIndex
].getPrevVector();
324 void setPrevVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
326 bool bWasUsed(mnUsedVectors
&& !maVector
[nIndex
].getPrevVector().equalZero());
327 bool bIsUsed(!rValue
.equalZero());
333 maVector
[nIndex
].setPrevVector(rValue
);
337 maVector
[nIndex
].setPrevVector(basegfx::B2DVector::getEmptyVector());
345 maVector
[nIndex
].setPrevVector(rValue
);
351 const basegfx::B2DVector
& getNextVector(sal_uInt32 nIndex
) const
353 return maVector
[nIndex
].getNextVector();
356 void setNextVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
358 bool bWasUsed(mnUsedVectors
&& !maVector
[nIndex
].getNextVector().equalZero());
359 bool bIsUsed(!rValue
.equalZero());
365 maVector
[nIndex
].setNextVector(rValue
);
369 maVector
[nIndex
].setNextVector(basegfx::B2DVector::getEmptyVector());
377 maVector
[nIndex
].setNextVector(rValue
);
383 void insert(sal_uInt32 nIndex
, const ControlVectorPair2D
& rValue
, sal_uInt32 nCount
)
387 // add nCount copies of rValue
388 ControlVectorPair2DVector::iterator
aIndex(maVector
.begin());
390 maVector
.insert(aIndex
, nCount
, rValue
);
392 if(!rValue
.getPrevVector().equalZero())
393 mnUsedVectors
+= nCount
;
395 if(!rValue
.getNextVector().equalZero())
396 mnUsedVectors
+= nCount
;
400 void insert(sal_uInt32 nIndex
, const ControlVectorArray2D
& rSource
)
402 const sal_uInt32
nCount(rSource
.maVector
.size());
407 ControlVectorPair2DVector::iterator
aIndex(maVector
.begin());
409 ControlVectorPair2DVector::const_iterator
aStart(rSource
.maVector
.begin());
410 ControlVectorPair2DVector::const_iterator
aEnd(rSource
.maVector
.end());
411 maVector
.insert(aIndex
, aStart
, aEnd
);
413 for(; aStart
!= aEnd
; aStart
++)
415 if(!aStart
->getPrevVector().equalZero())
418 if(!aStart
->getNextVector().equalZero())
424 void remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
428 const ControlVectorPair2DVector::iterator
aDeleteStart(maVector
.begin() + nIndex
);
429 const ControlVectorPair2DVector::iterator
aDeleteEnd(aDeleteStart
+ nCount
);
430 ControlVectorPair2DVector::const_iterator
aStart(aDeleteStart
);
432 for(; mnUsedVectors
&& aStart
!= aDeleteEnd
; aStart
++)
434 if(!aStart
->getPrevVector().equalZero())
437 if(mnUsedVectors
&& !aStart
->getNextVector().equalZero())
442 maVector
.erase(aDeleteStart
, aDeleteEnd
);
446 void flip(bool bIsClosed
)
448 if(maVector
.size() > 1)
450 // to keep the same point at index 0, just flip all points except the
451 // first one when closed
452 const sal_uInt32
nHalfSize(bIsClosed
? (maVector
.size() - 1) >> 1 : maVector
.size() >> 1);
453 ControlVectorPair2DVector::iterator
aStart(bIsClosed
? maVector
.begin() + 1 : maVector
.begin());
454 ControlVectorPair2DVector::iterator
aEnd(maVector
.end() - 1);
456 for(sal_uInt32
a(0); a
< nHalfSize
; a
++)
458 // swap Prev and Next
463 ::std::swap(*aStart
, *aEnd
);
471 // swap Prev and Next at middle element (if exists)
477 // swap Prev and Next at start element
478 maVector
.begin()->flip();
484 //////////////////////////////////////////////////////////////////////////////
486 class ImplBufferedData
489 // Possibility to hold the last subdivision
490 boost::scoped_ptr
< basegfx::B2DPolygon
> mpDefaultSubdivision
;
492 // Possibility to hold the last B2DRange calculation
493 boost::scoped_ptr
< basegfx::B2DRange
> mpB2DRange
;
497 : mpDefaultSubdivision(),
501 const basegfx::B2DPolygon
& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon
& rSource
) const
503 if(!mpDefaultSubdivision
)
505 const_cast< ImplBufferedData
* >(this)->mpDefaultSubdivision
.reset(new basegfx::B2DPolygon(basegfx::tools::adaptiveSubdivideByCount(rSource
, 9)));
508 return *mpDefaultSubdivision
;
511 const basegfx::B2DRange
& getB2DRange(const basegfx::B2DPolygon
& rSource
) const
515 basegfx::B2DRange aNewRange
;
516 const sal_uInt32
nPointCount(rSource
.count());
520 for(sal_uInt32
a(0); a
< nPointCount
; a
++)
522 aNewRange
.expand(rSource
.getB2DPoint(a
));
525 if(rSource
.areControlPointsUsed())
527 const sal_uInt32
nEdgeCount(rSource
.isClosed() ? nPointCount
: nPointCount
- 1);
531 basegfx::B2DCubicBezier aEdge
;
532 aEdge
.setStartPoint(rSource
.getB2DPoint(0));
534 for(sal_uInt32
b(0); b
< nEdgeCount
; b
++)
536 const sal_uInt32
nNextIndex((b
+ 1) % nPointCount
);
537 aEdge
.setControlPointA(rSource
.getNextControlPoint(b
));
538 aEdge
.setControlPointB(rSource
.getPrevControlPoint(nNextIndex
));
539 aEdge
.setEndPoint(rSource
.getB2DPoint(nNextIndex
));
543 const basegfx::B2DRange
aBezierRangeWithControlPoints(aEdge
.getRange());
545 if(!aNewRange
.isInside(aBezierRangeWithControlPoints
))
547 // the range with control points of the current edge is not completely
548 // inside the current range without control points. Expand current range by
549 // subdividing the bezier segment.
550 // Ideal here is a subdivision at the extreme values, so use
551 // getAllExtremumPositions to get all extremas in one run
552 ::std::vector
< double > aExtremas
;
554 aExtremas
.reserve(4);
555 aEdge
.getAllExtremumPositions(aExtremas
);
557 const sal_uInt32
nExtremaCount(aExtremas
.size());
559 for(sal_uInt32
c(0); c
< nExtremaCount
; c
++)
561 aNewRange
.expand(aEdge
.interpolatePoint(aExtremas
[c
]));
567 aEdge
.setStartPoint(aEdge
.getEndPoint());
573 const_cast< ImplBufferedData
* >(this)->mpB2DRange
.reset(new basegfx::B2DRange(aNewRange
));
580 //////////////////////////////////////////////////////////////////////////////
585 // The point vector. This vector exists always and defines the
587 CoordinateDataArray2D maPoints
;
589 // The control point vectors. This vectors are created on demand
591 boost::scoped_ptr
< ControlVectorArray2D
> mpControlVector
;
593 // buffered data for e.g. default subdivision and range
594 boost::scoped_ptr
< ImplBufferedData
> mpBufferedData
;
596 // flag which decides if this polygon is opened or closed
600 const basegfx::B2DPolygon
& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon
& rSource
) const
602 if(!mpControlVector
|| !mpControlVector
->isUsed())
609 const_cast< ImplB2DPolygon
* >(this)->mpBufferedData
.reset(new ImplBufferedData
);
612 return mpBufferedData
->getDefaultAdaptiveSubdivision(rSource
);
615 const basegfx::B2DRange
& getB2DRange(const basegfx::B2DPolygon
& rSource
) const
619 const_cast< ImplB2DPolygon
* >(this)->mpBufferedData
.reset(new ImplBufferedData
);
622 return mpBufferedData
->getB2DRange(rSource
);
632 ImplB2DPolygon(const ImplB2DPolygon
& rToBeCopied
)
633 : maPoints(rToBeCopied
.maPoints
),
636 mbIsClosed(rToBeCopied
.mbIsClosed
)
638 // complete initialization using copy
639 if(rToBeCopied
.mpControlVector
&& rToBeCopied
.mpControlVector
->isUsed())
641 mpControlVector
.reset( new ControlVectorArray2D(*rToBeCopied
.mpControlVector
) );
645 ImplB2DPolygon(const ImplB2DPolygon
& rToBeCopied
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
646 : maPoints(rToBeCopied
.maPoints
, nIndex
, nCount
),
649 mbIsClosed(rToBeCopied
.mbIsClosed
)
651 // complete initialization using partly copy
652 if(rToBeCopied
.mpControlVector
&& rToBeCopied
.mpControlVector
->isUsed())
654 mpControlVector
.reset( new ControlVectorArray2D(*rToBeCopied
.mpControlVector
, nIndex
, nCount
) );
656 if(!mpControlVector
->isUsed())
657 mpControlVector
.reset();
661 ImplB2DPolygon
& operator=( const ImplB2DPolygon
& rToBeCopied
)
663 maPoints
= rToBeCopied
.maPoints
;
664 mpControlVector
.reset();
665 mpBufferedData
.reset();
666 mbIsClosed
= rToBeCopied
.mbIsClosed
;
668 // complete initialization using copy
669 if(rToBeCopied
.mpControlVector
&& rToBeCopied
.mpControlVector
->isUsed())
670 mpControlVector
.reset( new ControlVectorArray2D(*rToBeCopied
.mpControlVector
) );
675 sal_uInt32
count() const
677 return maPoints
.count();
680 bool isClosed() const
685 void setClosed(bool bNew
)
687 if(bNew
!= mbIsClosed
)
689 mpBufferedData
.reset();
694 bool operator==(const ImplB2DPolygon
& rCandidate
) const
696 if(mbIsClosed
== rCandidate
.mbIsClosed
)
698 if(maPoints
== rCandidate
.maPoints
)
700 bool bControlVectorsAreEqual(true);
704 if(rCandidate
.mpControlVector
)
706 bControlVectorsAreEqual
= ((*mpControlVector
) == (*rCandidate
.mpControlVector
));
710 // candidate has no control vector, so it's assumed all unused.
711 bControlVectorsAreEqual
= !mpControlVector
->isUsed();
716 if(rCandidate
.mpControlVector
)
718 // we have no control vector, so it's assumed all unused.
719 bControlVectorsAreEqual
= !rCandidate
.mpControlVector
->isUsed();
723 if(bControlVectorsAreEqual
)
733 const basegfx::B2DPoint
& getPoint(sal_uInt32 nIndex
) const
735 return maPoints
.getCoordinate(nIndex
);
738 void setPoint(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rValue
)
740 mpBufferedData
.reset();
741 maPoints
.setCoordinate(nIndex
, rValue
);
744 void insert(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rPoint
, sal_uInt32 nCount
)
748 mpBufferedData
.reset();
749 CoordinateData2D
aCoordinate(rPoint
);
750 maPoints
.insert(nIndex
, aCoordinate
, nCount
);
754 ControlVectorPair2D aVectorPair
;
755 mpControlVector
->insert(nIndex
, aVectorPair
, nCount
);
760 const basegfx::B2DVector
& getPrevControlVector(sal_uInt32 nIndex
) const
764 return mpControlVector
->getPrevVector(nIndex
);
768 return basegfx::B2DVector::getEmptyVector();
772 void setPrevControlVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
776 if(!rValue
.equalZero())
778 mpBufferedData
.reset();
779 mpControlVector
.reset( new ControlVectorArray2D(maPoints
.count()) );
780 mpControlVector
->setPrevVector(nIndex
, rValue
);
785 mpBufferedData
.reset();
786 mpControlVector
->setPrevVector(nIndex
, rValue
);
788 if(!mpControlVector
->isUsed())
789 mpControlVector
.reset();
793 const basegfx::B2DVector
& getNextControlVector(sal_uInt32 nIndex
) const
797 return mpControlVector
->getNextVector(nIndex
);
801 return basegfx::B2DVector::getEmptyVector();
805 void setNextControlVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
809 if(!rValue
.equalZero())
811 mpBufferedData
.reset();
812 mpControlVector
.reset( new ControlVectorArray2D(maPoints
.count()) );
813 mpControlVector
->setNextVector(nIndex
, rValue
);
818 mpBufferedData
.reset();
819 mpControlVector
->setNextVector(nIndex
, rValue
);
821 if(!mpControlVector
->isUsed())
822 mpControlVector
.reset();
826 bool areControlPointsUsed() const
828 return (mpControlVector
&& mpControlVector
->isUsed());
831 void resetControlVectors(sal_uInt32 nIndex
)
833 setPrevControlVector(nIndex
, basegfx::B2DVector::getEmptyVector());
834 setNextControlVector(nIndex
, basegfx::B2DVector::getEmptyVector());
837 void resetControlVectors()
839 mpBufferedData
.reset();
840 mpControlVector
.reset();
843 void setControlVectors(sal_uInt32 nIndex
, const basegfx::B2DVector
& rPrev
, const basegfx::B2DVector
& rNext
)
845 setPrevControlVector(nIndex
, rPrev
);
846 setNextControlVector(nIndex
, rNext
);
849 void appendBezierSegment(const basegfx::B2DVector
& rNext
, const basegfx::B2DVector
& rPrev
, const basegfx::B2DPoint
& rPoint
)
851 mpBufferedData
.reset();
852 const sal_uInt32
nCount(maPoints
.count());
856 setNextControlVector(nCount
- 1, rNext
);
859 insert(nCount
, rPoint
, 1);
860 setPrevControlVector(nCount
, rPrev
);
863 void insert(sal_uInt32 nIndex
, const ImplB2DPolygon
& rSource
)
865 const sal_uInt32
nCount(rSource
.maPoints
.count());
869 mpBufferedData
.reset();
871 if(rSource
.mpControlVector
&& rSource
.mpControlVector
->isUsed() && !mpControlVector
)
873 mpControlVector
.reset( new ControlVectorArray2D(maPoints
.count()) );
876 maPoints
.insert(nIndex
, rSource
.maPoints
);
878 if(rSource
.mpControlVector
)
880 mpControlVector
->insert(nIndex
, *rSource
.mpControlVector
);
882 if(!mpControlVector
->isUsed())
883 mpControlVector
.reset();
885 else if(mpControlVector
)
887 ControlVectorPair2D aVectorPair
;
888 mpControlVector
->insert(nIndex
, aVectorPair
, nCount
);
893 void remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
897 mpBufferedData
.reset();
898 maPoints
.remove(nIndex
, nCount
);
902 mpControlVector
->remove(nIndex
, nCount
);
904 if(!mpControlVector
->isUsed())
905 mpControlVector
.reset();
912 if(maPoints
.count() > 1)
914 mpBufferedData
.reset();
917 maPoints
.flip(mbIsClosed
);
921 // flip control vector
922 mpControlVector
->flip(mbIsClosed
);
927 bool hasDoublePoints() const
931 // check for same start and end point
932 const sal_uInt32
nIndex(maPoints
.count() - 1);
934 if(maPoints
.getCoordinate(0) == maPoints
.getCoordinate(nIndex
))
938 if(mpControlVector
->getNextVector(nIndex
).equalZero() && mpControlVector
->getPrevVector(0).equalZero())
951 for(sal_uInt32
a(0); a
< maPoints
.count() - 1; a
++)
953 if(maPoints
.getCoordinate(a
) == maPoints
.getCoordinate(a
+ 1))
957 if(mpControlVector
->getNextVector(a
).equalZero() && mpControlVector
->getPrevVector(a
+ 1).equalZero())
972 void removeDoublePointsAtBeginEnd()
974 // Only remove DoublePoints at Begin and End when poly is closed
977 mpBufferedData
.reset();
987 if(maPoints
.count() > 1)
989 const sal_uInt32
nIndex(maPoints
.count() - 1);
991 if(maPoints
.getCoordinate(0) == maPoints
.getCoordinate(nIndex
))
995 if(mpControlVector
->getNextVector(nIndex
).equalZero() && mpControlVector
->getPrevVector(0).equalZero())
1009 const sal_uInt32
nIndex(maPoints
.count() - 1);
1011 if(mpControlVector
&& !mpControlVector
->getPrevVector(nIndex
).equalZero())
1013 mpControlVector
->setPrevVector(0, mpControlVector
->getPrevVector(nIndex
));
1023 maPoints
.removeDoublePointsAtBeginEnd();
1028 void removeDoublePointsWholeTrack()
1030 mpBufferedData
.reset();
1034 sal_uInt32
nIndex(0);
1036 // test as long as there are at least two points and as long as the index
1037 // is smaller or equal second last point
1038 while((maPoints
.count() > 1) && (nIndex
<= maPoints
.count() - 2))
1040 bool bRemove(maPoints
.getCoordinate(nIndex
) == maPoints
.getCoordinate(nIndex
+ 1));
1046 if(!mpControlVector
->getNextVector(nIndex
).equalZero() || !mpControlVector
->getPrevVector(nIndex
+ 1).equalZero())
1055 if(mpControlVector
&& !mpControlVector
->getPrevVector(nIndex
).equalZero())
1057 mpControlVector
->setPrevVector(nIndex
+ 1, mpControlVector
->getPrevVector(nIndex
));
1060 // if next is same as index and the control vectors are unused, delete index
1065 // if different, step forward
1072 maPoints
.removeDoublePointsWholeTrack();
1076 void transform(const basegfx::B2DHomMatrix
& rMatrix
)
1078 mpBufferedData
.reset();
1082 for(sal_uInt32
a(0); a
< maPoints
.count(); a
++)
1084 basegfx::B2DPoint aCandidate
= maPoints
.getCoordinate(a
);
1086 if(mpControlVector
->isUsed())
1088 const basegfx::B2DVector
& rPrevVector(mpControlVector
->getPrevVector(a
));
1089 const basegfx::B2DVector
& rNextVector(mpControlVector
->getNextVector(a
));
1091 if(!rPrevVector
.equalZero())
1093 basegfx::B2DVector
aPrevVector(rMatrix
* rPrevVector
);
1094 mpControlVector
->setPrevVector(a
, aPrevVector
);
1097 if(!rNextVector
.equalZero())
1099 basegfx::B2DVector
aNextVector(rMatrix
* rNextVector
);
1100 mpControlVector
->setNextVector(a
, aNextVector
);
1104 aCandidate
*= rMatrix
;
1105 maPoints
.setCoordinate(a
, aCandidate
);
1108 if(!mpControlVector
->isUsed())
1109 mpControlVector
.reset();
1113 maPoints
.transform(rMatrix
);
1118 //////////////////////////////////////////////////////////////////////////////
1124 struct DefaultPolygon
: public rtl::Static
<B2DPolygon::ImplType
, DefaultPolygon
> {};
1127 B2DPolygon::B2DPolygon()
1128 : mpPolygon(DefaultPolygon::get())
1131 B2DPolygon::B2DPolygon(const B2DPolygon
& rPolygon
)
1132 : mpPolygon(rPolygon
.mpPolygon
)
1135 B2DPolygon::B2DPolygon(const B2DPolygon
& rPolygon
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
1136 : mpPolygon(ImplB2DPolygon(*rPolygon
.mpPolygon
, nIndex
, nCount
))
1138 // TODO(P2): one extra temporary here (cow_wrapper copies
1139 // given ImplB2DPolygon into its internal impl_t wrapper type)
1140 OSL_ENSURE(nIndex
+ nCount
<= rPolygon
.mpPolygon
->count(), "B2DPolygon constructor outside range (!)");
1143 B2DPolygon::~B2DPolygon()
1147 B2DPolygon
& B2DPolygon::operator=(const B2DPolygon
& rPolygon
)
1149 mpPolygon
= rPolygon
.mpPolygon
;
1153 void B2DPolygon::makeUnique()
1155 mpPolygon
.make_unique();
1158 bool B2DPolygon::operator==(const B2DPolygon
& rPolygon
) const
1160 if(mpPolygon
.same_object(rPolygon
.mpPolygon
))
1163 return ((*mpPolygon
) == (*rPolygon
.mpPolygon
));
1166 bool B2DPolygon::operator!=(const B2DPolygon
& rPolygon
) const
1168 return !(*this == rPolygon
);
1171 sal_uInt32
B2DPolygon::count() const
1173 return mpPolygon
->count();
1176 B2DPoint
B2DPolygon::getB2DPoint(sal_uInt32 nIndex
) const
1178 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1180 return mpPolygon
->getPoint(nIndex
);
1183 void B2DPolygon::setB2DPoint(sal_uInt32 nIndex
, const B2DPoint
& rValue
)
1185 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1187 if(getB2DPoint(nIndex
) != rValue
)
1189 mpPolygon
->setPoint(nIndex
, rValue
);
1193 void B2DPolygon::insert(sal_uInt32 nIndex
, const B2DPoint
& rPoint
, sal_uInt32 nCount
)
1195 OSL_ENSURE(nIndex
<= mpPolygon
->count(), "B2DPolygon Insert outside range (!)");
1199 mpPolygon
->insert(nIndex
, rPoint
, nCount
);
1203 void B2DPolygon::append(const B2DPoint
& rPoint
, sal_uInt32 nCount
)
1207 mpPolygon
->insert(mpPolygon
->count(), rPoint
, nCount
);
1211 B2DPoint
B2DPolygon::getPrevControlPoint(sal_uInt32 nIndex
) const
1213 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1215 if(mpPolygon
->areControlPointsUsed())
1217 return mpPolygon
->getPoint(nIndex
) + mpPolygon
->getPrevControlVector(nIndex
);
1221 return mpPolygon
->getPoint(nIndex
);
1225 B2DPoint
B2DPolygon::getNextControlPoint(sal_uInt32 nIndex
) const
1227 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1229 if(mpPolygon
->areControlPointsUsed())
1231 return mpPolygon
->getPoint(nIndex
) + mpPolygon
->getNextControlVector(nIndex
);
1235 return mpPolygon
->getPoint(nIndex
);
1239 void B2DPolygon::setPrevControlPoint(sal_uInt32 nIndex
, const B2DPoint
& rValue
)
1241 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1242 const basegfx::B2DVector
aNewVector(rValue
- mpPolygon
->getPoint(nIndex
));
1244 if(mpPolygon
->getPrevControlVector(nIndex
) != aNewVector
)
1246 mpPolygon
->setPrevControlVector(nIndex
, aNewVector
);
1250 void B2DPolygon::setNextControlPoint(sal_uInt32 nIndex
, const B2DPoint
& rValue
)
1252 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1253 const basegfx::B2DVector
aNewVector(rValue
- mpPolygon
->getPoint(nIndex
));
1255 if(mpPolygon
->getNextControlVector(nIndex
) != aNewVector
)
1257 mpPolygon
->setNextControlVector(nIndex
, aNewVector
);
1261 void B2DPolygon::setControlPoints(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rPrev
, const basegfx::B2DPoint
& rNext
)
1263 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1264 const B2DPoint
aPoint(mpPolygon
->getPoint(nIndex
));
1265 const basegfx::B2DVector
aNewPrev(rPrev
- aPoint
);
1266 const basegfx::B2DVector
aNewNext(rNext
- aPoint
);
1268 if(mpPolygon
->getPrevControlVector(nIndex
) != aNewPrev
|| mpPolygon
->getNextControlVector(nIndex
) != aNewNext
)
1270 mpPolygon
->setControlVectors(nIndex
, aNewPrev
, aNewNext
);
1274 void B2DPolygon::resetPrevControlPoint(sal_uInt32 nIndex
)
1276 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1278 if(mpPolygon
->areControlPointsUsed() && !mpPolygon
->getPrevControlVector(nIndex
).equalZero())
1280 mpPolygon
->setPrevControlVector(nIndex
, B2DVector::getEmptyVector());
1284 void B2DPolygon::resetNextControlPoint(sal_uInt32 nIndex
)
1286 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1288 if(mpPolygon
->areControlPointsUsed() && !mpPolygon
->getNextControlVector(nIndex
).equalZero())
1290 mpPolygon
->setNextControlVector(nIndex
, B2DVector::getEmptyVector());
1294 void B2DPolygon::resetControlPoints(sal_uInt32 nIndex
)
1296 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1298 if(mpPolygon
->areControlPointsUsed() &&
1299 (!mpPolygon
->getPrevControlVector(nIndex
).equalZero() || !mpPolygon
->getNextControlVector(nIndex
).equalZero()))
1301 mpPolygon
->resetControlVectors(nIndex
);
1305 void B2DPolygon::resetControlPoints()
1307 if(mpPolygon
->areControlPointsUsed())
1309 mpPolygon
->resetControlVectors();
1313 void B2DPolygon::appendBezierSegment(
1314 const B2DPoint
& rNextControlPoint
,
1315 const B2DPoint
& rPrevControlPoint
,
1316 const B2DPoint
& rPoint
)
1318 const B2DVector
aNewNextVector(mpPolygon
->count() ? B2DVector(rNextControlPoint
- mpPolygon
->getPoint(mpPolygon
->count() - 1)) : B2DVector::getEmptyVector());
1319 const B2DVector
aNewPrevVector(rPrevControlPoint
- rPoint
);
1321 if(aNewNextVector
.equalZero() && aNewPrevVector
.equalZero())
1323 mpPolygon
->insert(mpPolygon
->count(), rPoint
, 1);
1327 mpPolygon
->appendBezierSegment(aNewNextVector
, aNewPrevVector
, rPoint
);
1331 bool B2DPolygon::areControlPointsUsed() const
1333 return mpPolygon
->areControlPointsUsed();
1336 bool B2DPolygon::isPrevControlPointUsed(sal_uInt32 nIndex
) const
1338 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1340 return (mpPolygon
->areControlPointsUsed() && !mpPolygon
->getPrevControlVector(nIndex
).equalZero());
1343 bool B2DPolygon::isNextControlPointUsed(sal_uInt32 nIndex
) const
1345 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1347 return (mpPolygon
->areControlPointsUsed() && !mpPolygon
->getNextControlVector(nIndex
).equalZero());
1350 B2VectorContinuity
B2DPolygon::getContinuityInPoint(sal_uInt32 nIndex
) const
1352 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1354 if(mpPolygon
->areControlPointsUsed())
1356 const B2DVector
& rPrev(mpPolygon
->getPrevControlVector(nIndex
));
1357 const B2DVector
& rNext(mpPolygon
->getNextControlVector(nIndex
));
1359 return getContinuity(rPrev
, rNext
);
1363 return CONTINUITY_NONE
;
1367 bool B2DPolygon::isBezierSegment(sal_uInt32 nIndex
) const
1369 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1371 if(mpPolygon
->areControlPointsUsed())
1373 // Check if the edge exists
1374 const bool bNextIndexValidWithoutClose(nIndex
+ 1 < mpPolygon
->count());
1376 if(bNextIndexValidWithoutClose
|| mpPolygon
->isClosed())
1378 const sal_uInt32
nNextIndex(bNextIndexValidWithoutClose
? nIndex
+ 1 : 0);
1379 return (!mpPolygon
->getPrevControlVector(nNextIndex
).equalZero()
1380 || !mpPolygon
->getNextControlVector(nIndex
).equalZero());
1384 // no valid edge -> no bezier segment, even when local next
1385 // vector may be used
1391 // no control points -> no bezier segment
1396 void B2DPolygon::getBezierSegment(sal_uInt32 nIndex
, B2DCubicBezier
& rTarget
) const
1398 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1399 const bool bNextIndexValidWithoutClose(nIndex
+ 1 < mpPolygon
->count());
1401 if(bNextIndexValidWithoutClose
|| mpPolygon
->isClosed())
1403 const sal_uInt32
nNextIndex(bNextIndexValidWithoutClose
? nIndex
+ 1 : 0);
1404 rTarget
.setStartPoint(mpPolygon
->getPoint(nIndex
));
1405 rTarget
.setEndPoint(mpPolygon
->getPoint(nNextIndex
));
1407 if(mpPolygon
->areControlPointsUsed())
1409 rTarget
.setControlPointA(rTarget
.getStartPoint() + mpPolygon
->getNextControlVector(nIndex
));
1410 rTarget
.setControlPointB(rTarget
.getEndPoint() + mpPolygon
->getPrevControlVector(nNextIndex
));
1414 // no bezier, reset control poins at rTarget
1415 rTarget
.setControlPointA(rTarget
.getStartPoint());
1416 rTarget
.setControlPointB(rTarget
.getEndPoint());
1421 // no valid edge at all, reset rTarget to current point
1422 const B2DPoint
aPoint(mpPolygon
->getPoint(nIndex
));
1423 rTarget
.setStartPoint(aPoint
);
1424 rTarget
.setEndPoint(aPoint
);
1425 rTarget
.setControlPointA(aPoint
);
1426 rTarget
.setControlPointB(aPoint
);
1430 B2DPolygon
B2DPolygon::getDefaultAdaptiveSubdivision() const
1432 return mpPolygon
->getDefaultAdaptiveSubdivision(*this);
1435 B2DRange
B2DPolygon::getB2DRange() const
1437 return mpPolygon
->getB2DRange(*this);
1440 void B2DPolygon::insert(sal_uInt32 nIndex
, const B2DPolygon
& rPoly
, sal_uInt32 nIndex2
, sal_uInt32 nCount
)
1442 OSL_ENSURE(nIndex
<= mpPolygon
->count(), "B2DPolygon Insert outside range (!)");
1448 nCount
= rPoly
.count();
1451 if(0 == nIndex2
&& nCount
== rPoly
.count())
1453 mpPolygon
->insert(nIndex
, *rPoly
.mpPolygon
);
1457 OSL_ENSURE(nIndex2
+ nCount
<= rPoly
.mpPolygon
->count(), "B2DPolygon Insert outside range (!)");
1458 ImplB2DPolygon
aTempPoly(*rPoly
.mpPolygon
, nIndex2
, nCount
);
1459 mpPolygon
->insert(nIndex
, aTempPoly
);
1464 void B2DPolygon::append(const B2DPolygon
& rPoly
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
1470 nCount
= rPoly
.count();
1473 if(0 == nIndex
&& nCount
== rPoly
.count())
1475 mpPolygon
->insert(mpPolygon
->count(), *rPoly
.mpPolygon
);
1479 OSL_ENSURE(nIndex
+ nCount
<= rPoly
.mpPolygon
->count(), "B2DPolygon Append outside range (!)");
1480 ImplB2DPolygon
aTempPoly(*rPoly
.mpPolygon
, nIndex
, nCount
);
1481 mpPolygon
->insert(mpPolygon
->count(), aTempPoly
);
1486 void B2DPolygon::remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
1488 OSL_ENSURE(nIndex
+ nCount
<= mpPolygon
->count(), "B2DPolygon Remove outside range (!)");
1492 mpPolygon
->remove(nIndex
, nCount
);
1496 void B2DPolygon::clear()
1498 mpPolygon
= DefaultPolygon::get();
1501 bool B2DPolygon::isClosed() const
1503 return mpPolygon
->isClosed();
1506 void B2DPolygon::setClosed(bool bNew
)
1508 if(isClosed() != bNew
)
1510 mpPolygon
->setClosed(bNew
);
1514 void B2DPolygon::flip()
1522 bool B2DPolygon::hasDoublePoints() const
1524 return (mpPolygon
->count() > 1 && mpPolygon
->hasDoublePoints());
1527 void B2DPolygon::removeDoublePoints()
1529 if(hasDoublePoints())
1531 mpPolygon
->removeDoublePointsAtBeginEnd();
1532 mpPolygon
->removeDoublePointsWholeTrack();
1536 void B2DPolygon::transform(const B2DHomMatrix
& rMatrix
)
1538 if(mpPolygon
->count() && !rMatrix
.isIdentity())
1540 mpPolygon
->transform(rMatrix
);
1543 } // end of namespace basegfx
1545 //////////////////////////////////////////////////////////////////////////////