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 struct CoordinateData2D
: public basegfx::B2DPoint
37 explicit CoordinateData2D(const basegfx::B2DPoint
& rData
)
41 CoordinateData2D
& operator=(const basegfx::B2DPoint
& rData
)
43 B2DPoint::operator=(rData
);
47 void transform(const basegfx::B2DHomMatrix
& rMatrix
)
53 class CoordinateDataArray2D
55 typedef ::std::vector
< CoordinateData2D
> CoordinateData2DVector
;
57 CoordinateData2DVector maVector
;
60 explicit CoordinateDataArray2D(sal_uInt32 nCount
)
65 explicit CoordinateDataArray2D(const CoordinateDataArray2D
& rOriginal
)
66 : maVector(rOriginal
.maVector
)
70 CoordinateDataArray2D(const CoordinateDataArray2D
& rOriginal
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
71 : maVector(rOriginal
.maVector
.begin() + nIndex
, rOriginal
.maVector
.begin() + (nIndex
+ nCount
))
75 sal_uInt32
count() const
77 return maVector
.size();
80 bool operator==(const CoordinateDataArray2D
& rCandidate
) const
82 return (maVector
== rCandidate
.maVector
);
85 const basegfx::B2DPoint
& getCoordinate(sal_uInt32 nIndex
) const
87 return maVector
[nIndex
];
90 void setCoordinate(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rValue
)
92 maVector
[nIndex
] = rValue
;
95 void reserve(sal_uInt32 nCount
)
97 maVector
.reserve(nCount
);
100 void append(const CoordinateData2D
& rValue
)
102 maVector
.push_back(rValue
);
105 void insert(sal_uInt32 nIndex
, const CoordinateData2D
& rValue
, sal_uInt32 nCount
)
109 // add nCount copies of rValue
110 CoordinateData2DVector::iterator
aIndex(maVector
.begin());
112 maVector
.insert(aIndex
, nCount
, rValue
);
116 void insert(sal_uInt32 nIndex
, const CoordinateDataArray2D
& rSource
)
118 const sal_uInt32
nCount(rSource
.maVector
.size());
123 CoordinateData2DVector::iterator
aIndex(maVector
.begin());
125 CoordinateData2DVector::const_iterator
aStart(rSource
.maVector
.begin());
126 CoordinateData2DVector::const_iterator
aEnd(rSource
.maVector
.end());
127 maVector
.insert(aIndex
, aStart
, aEnd
);
131 void remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
136 CoordinateData2DVector::iterator
aStart(maVector
.begin());
138 const CoordinateData2DVector::iterator
aEnd(aStart
+ nCount
);
139 maVector
.erase(aStart
, aEnd
);
143 void flip(bool bIsClosed
)
145 if(maVector
.size() > 1)
147 // to keep the same point at index 0, just flip all points except the
148 // first one when closed
149 const sal_uInt32
nHalfSize(bIsClosed
? (maVector
.size() - 1) >> 1 : maVector
.size() >> 1);
150 CoordinateData2DVector::iterator
aStart(bIsClosed
? maVector
.begin() + 1 : maVector
.begin());
151 CoordinateData2DVector::iterator
aEnd(maVector
.end() - 1);
153 for(sal_uInt32
a(0); a
< nHalfSize
; a
++)
155 ::std::swap(*aStart
, *aEnd
);
162 void removeDoublePointsAtBeginEnd()
164 // remove from end as long as there are at least two points
165 // and begin/end are equal
166 while((maVector
.size() > 1) && (maVector
[0] == maVector
[maVector
.size() - 1]))
172 void removeDoublePointsWholeTrack()
174 sal_uInt32
nIndex(0);
176 // test as long as there are at least two points and as long as the index
177 // is smaller or equal second last point
178 while((maVector
.size() > 1) && (nIndex
<= maVector
.size() - 2))
180 if(maVector
[nIndex
] == maVector
[nIndex
+ 1])
182 // if next is same as index, delete next
183 maVector
.erase(maVector
.begin() + (nIndex
+ 1));
187 // if different, step forward
193 void transform(const basegfx::B2DHomMatrix
& rMatrix
)
195 CoordinateData2DVector::iterator
aStart(maVector
.begin());
196 CoordinateData2DVector::iterator
aEnd(maVector
.end());
198 for(; aStart
!= aEnd
; ++aStart
)
200 aStart
->transform(rMatrix
);
205 class ControlVectorPair2D
207 basegfx::B2DVector maPrevVector
;
208 basegfx::B2DVector maNextVector
;
211 explicit ControlVectorPair2D() {}
213 const basegfx::B2DVector
& getPrevVector() const
218 void setPrevVector(const basegfx::B2DVector
& rValue
)
220 if(rValue
!= maPrevVector
)
221 maPrevVector
= rValue
;
224 const basegfx::B2DVector
& getNextVector() const
229 void setNextVector(const basegfx::B2DVector
& rValue
)
231 if(rValue
!= maNextVector
)
232 maNextVector
= rValue
;
235 bool operator==(const ControlVectorPair2D
& rData
) const
237 return (maPrevVector
== rData
.getPrevVector() && maNextVector
== rData
.getNextVector());
242 ::std::swap(maPrevVector
, maNextVector
);
246 class ControlVectorArray2D
248 typedef ::std::vector
< ControlVectorPair2D
> ControlVectorPair2DVector
;
250 ControlVectorPair2DVector maVector
;
251 sal_uInt32 mnUsedVectors
;
254 explicit ControlVectorArray2D(sal_uInt32 nCount
)
259 ControlVectorArray2D(const ControlVectorArray2D
& rOriginal
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
263 ControlVectorPair2DVector::const_iterator
aStart(rOriginal
.maVector
.begin());
265 ControlVectorPair2DVector::const_iterator
aEnd(aStart
);
267 maVector
.reserve(nCount
);
269 for(; aStart
!= aEnd
; ++aStart
)
271 if(!aStart
->getPrevVector().equalZero())
274 if(!aStart
->getNextVector().equalZero())
277 maVector
.push_back(*aStart
);
281 bool operator==(const ControlVectorArray2D
& rCandidate
) const
283 return (maVector
== rCandidate
.maVector
);
288 return (0 != mnUsedVectors
);
291 const basegfx::B2DVector
& getPrevVector(sal_uInt32 nIndex
) const
293 return maVector
[nIndex
].getPrevVector();
296 void setPrevVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
298 bool bWasUsed(mnUsedVectors
&& !maVector
[nIndex
].getPrevVector().equalZero());
299 bool bIsUsed(!rValue
.equalZero());
305 maVector
[nIndex
].setPrevVector(rValue
);
309 maVector
[nIndex
].setPrevVector(basegfx::B2DVector::getEmptyVector());
317 maVector
[nIndex
].setPrevVector(rValue
);
323 const basegfx::B2DVector
& getNextVector(sal_uInt32 nIndex
) const
325 return maVector
[nIndex
].getNextVector();
328 void setNextVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
330 bool bWasUsed(mnUsedVectors
&& !maVector
[nIndex
].getNextVector().equalZero());
331 bool bIsUsed(!rValue
.equalZero());
337 maVector
[nIndex
].setNextVector(rValue
);
341 maVector
[nIndex
].setNextVector(basegfx::B2DVector::getEmptyVector());
349 maVector
[nIndex
].setNextVector(rValue
);
355 void append(const ControlVectorPair2D
& rValue
)
357 maVector
.push_back(rValue
);
359 if(!rValue
.getPrevVector().equalZero())
362 if(!rValue
.getNextVector().equalZero())
366 void insert(sal_uInt32 nIndex
, const ControlVectorPair2D
& rValue
, sal_uInt32 nCount
)
370 // add nCount copies of rValue
371 ControlVectorPair2DVector::iterator
aIndex(maVector
.begin());
373 maVector
.insert(aIndex
, nCount
, rValue
);
375 if(!rValue
.getPrevVector().equalZero())
376 mnUsedVectors
+= nCount
;
378 if(!rValue
.getNextVector().equalZero())
379 mnUsedVectors
+= nCount
;
383 void insert(sal_uInt32 nIndex
, const ControlVectorArray2D
& rSource
)
385 const sal_uInt32
nCount(rSource
.maVector
.size());
390 ControlVectorPair2DVector::iterator
aIndex(maVector
.begin());
392 ControlVectorPair2DVector::const_iterator
aStart(rSource
.maVector
.begin());
393 ControlVectorPair2DVector::const_iterator
aEnd(rSource
.maVector
.end());
394 maVector
.insert(aIndex
, aStart
, aEnd
);
396 for(; aStart
!= aEnd
; ++aStart
)
398 if(!aStart
->getPrevVector().equalZero())
401 if(!aStart
->getNextVector().equalZero())
407 void remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
411 const ControlVectorPair2DVector::iterator
aDeleteStart(maVector
.begin() + nIndex
);
412 const ControlVectorPair2DVector::iterator
aDeleteEnd(aDeleteStart
+ nCount
);
413 ControlVectorPair2DVector::const_iterator
aStart(aDeleteStart
);
415 for(; mnUsedVectors
&& aStart
!= aDeleteEnd
; ++aStart
)
417 if(!aStart
->getPrevVector().equalZero())
420 if(mnUsedVectors
&& !aStart
->getNextVector().equalZero())
425 maVector
.erase(aDeleteStart
, aDeleteEnd
);
429 void flip(bool bIsClosed
)
431 if(maVector
.size() > 1)
433 // to keep the same point at index 0, just flip all points except the
434 // first one when closed
435 const sal_uInt32
nHalfSize(bIsClosed
? (maVector
.size() - 1) >> 1 : maVector
.size() >> 1);
436 ControlVectorPair2DVector::iterator
aStart(bIsClosed
? maVector
.begin() + 1 : maVector
.begin());
437 ControlVectorPair2DVector::iterator
aEnd(maVector
.end() - 1);
439 for(sal_uInt32
a(0); a
< nHalfSize
; a
++)
441 // swap Prev and Next
446 ::std::swap(*aStart
, *aEnd
);
454 // swap Prev and Next at middle element (if exists)
460 // swap Prev and Next at start element
461 maVector
.begin()->flip();
467 class ImplBufferedData
470 // Possibility to hold the last subdivision
471 boost::scoped_ptr
< basegfx::B2DPolygon
> mpDefaultSubdivision
;
473 // Possibility to hold the last B2DRange calculation
474 boost::scoped_ptr
< basegfx::B2DRange
> mpB2DRange
;
478 : mpDefaultSubdivision(),
482 const basegfx::B2DPolygon
& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon
& rSource
) const
484 if(!mpDefaultSubdivision
)
486 const_cast< ImplBufferedData
* >(this)->mpDefaultSubdivision
.reset(new basegfx::B2DPolygon(basegfx::tools::adaptiveSubdivideByCount(rSource
, 9)));
489 return *mpDefaultSubdivision
;
492 const basegfx::B2DRange
& getB2DRange(const basegfx::B2DPolygon
& rSource
) const
496 basegfx::B2DRange aNewRange
;
497 const sal_uInt32
nPointCount(rSource
.count());
501 for(sal_uInt32
a(0); a
< nPointCount
; a
++)
503 aNewRange
.expand(rSource
.getB2DPoint(a
));
506 if(rSource
.areControlPointsUsed())
508 const sal_uInt32
nEdgeCount(rSource
.isClosed() ? nPointCount
: nPointCount
- 1);
512 basegfx::B2DCubicBezier aEdge
;
513 aEdge
.setStartPoint(rSource
.getB2DPoint(0));
515 for(sal_uInt32
b(0); b
< nEdgeCount
; b
++)
517 const sal_uInt32
nNextIndex((b
+ 1) % nPointCount
);
518 aEdge
.setControlPointA(rSource
.getNextControlPoint(b
));
519 aEdge
.setControlPointB(rSource
.getPrevControlPoint(nNextIndex
));
520 aEdge
.setEndPoint(rSource
.getB2DPoint(nNextIndex
));
524 const basegfx::B2DRange
aBezierRangeWithControlPoints(aEdge
.getRange());
526 if(!aNewRange
.isInside(aBezierRangeWithControlPoints
))
528 // the range with control points of the current edge is not completely
529 // inside the current range without control points. Expand current range by
530 // subdividing the bezier segment.
531 // Ideal here is a subdivision at the extreme values, so use
532 // getAllExtremumPositions to get all extremas in one run
533 ::std::vector
< double > aExtremas
;
535 aExtremas
.reserve(4);
536 aEdge
.getAllExtremumPositions(aExtremas
);
538 const sal_uInt32
nExtremaCount(aExtremas
.size());
540 for(sal_uInt32
c(0); c
< nExtremaCount
; c
++)
542 aNewRange
.expand(aEdge
.interpolatePoint(aExtremas
[c
]));
548 aEdge
.setStartPoint(aEdge
.getEndPoint());
554 const_cast< ImplBufferedData
* >(this)->mpB2DRange
.reset(new basegfx::B2DRange(aNewRange
));
564 // The point vector. This vector exists always and defines the
566 CoordinateDataArray2D maPoints
;
568 // The control point vectors. This vectors are created on demand
570 boost::scoped_ptr
< ControlVectorArray2D
> mpControlVector
;
572 // buffered data for e.g. default subdivision and range
573 boost::scoped_ptr
< ImplBufferedData
> mpBufferedData
;
575 // flag which decides if this polygon is opened or closed
579 const basegfx::B2DPolygon
& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon
& rSource
) const
581 if(!mpControlVector
|| !mpControlVector
->isUsed())
588 const_cast< ImplB2DPolygon
* >(this)->mpBufferedData
.reset(new ImplBufferedData
);
591 return mpBufferedData
->getDefaultAdaptiveSubdivision(rSource
);
594 const basegfx::B2DRange
& getB2DRange(const basegfx::B2DPolygon
& rSource
) const
598 const_cast< ImplB2DPolygon
* >(this)->mpBufferedData
.reset(new ImplBufferedData
);
601 return mpBufferedData
->getB2DRange(rSource
);
611 ImplB2DPolygon(const ImplB2DPolygon
& rToBeCopied
)
612 : maPoints(rToBeCopied
.maPoints
),
615 mbIsClosed(rToBeCopied
.mbIsClosed
)
617 // complete initialization using copy
618 if(rToBeCopied
.mpControlVector
&& rToBeCopied
.mpControlVector
->isUsed())
620 mpControlVector
.reset( new ControlVectorArray2D(*rToBeCopied
.mpControlVector
) );
624 ImplB2DPolygon(const ImplB2DPolygon
& rToBeCopied
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
625 : maPoints(rToBeCopied
.maPoints
, nIndex
, nCount
),
628 mbIsClosed(rToBeCopied
.mbIsClosed
)
630 // complete initialization using partly copy
631 if(rToBeCopied
.mpControlVector
&& rToBeCopied
.mpControlVector
->isUsed())
633 mpControlVector
.reset( new ControlVectorArray2D(*rToBeCopied
.mpControlVector
, nIndex
, nCount
) );
635 if(!mpControlVector
->isUsed())
636 mpControlVector
.reset();
640 ImplB2DPolygon
& operator=( const ImplB2DPolygon
& ) SAL_DELETED_FUNCTION
;
642 sal_uInt32
count() const
644 return maPoints
.count();
647 bool isClosed() const
652 void setClosed(bool bNew
)
654 if(bNew
!= mbIsClosed
)
656 mpBufferedData
.reset();
661 bool operator==(const ImplB2DPolygon
& rCandidate
) const
663 if(mbIsClosed
== rCandidate
.mbIsClosed
)
665 if(maPoints
== rCandidate
.maPoints
)
667 bool bControlVectorsAreEqual(true);
671 if(rCandidate
.mpControlVector
)
673 bControlVectorsAreEqual
= ((*mpControlVector
) == (*rCandidate
.mpControlVector
));
677 // candidate has no control vector, so it's assumed all unused.
678 bControlVectorsAreEqual
= !mpControlVector
->isUsed();
683 if(rCandidate
.mpControlVector
)
685 // we have no control vector, so it's assumed all unused.
686 bControlVectorsAreEqual
= !rCandidate
.mpControlVector
->isUsed();
690 if(bControlVectorsAreEqual
)
700 const basegfx::B2DPoint
& getPoint(sal_uInt32 nIndex
) const
702 return maPoints
.getCoordinate(nIndex
);
705 void setPoint(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rValue
)
707 mpBufferedData
.reset();
708 maPoints
.setCoordinate(nIndex
, rValue
);
711 void reserve(sal_uInt32 nCount
)
713 maPoints
.reserve(nCount
);
716 void append(const basegfx::B2DPoint
& rPoint
)
718 mpBufferedData
.reset(); // TODO: is this needed?
719 const CoordinateData2D
aCoordinate(rPoint
);
720 maPoints
.append(aCoordinate
);
724 const ControlVectorPair2D aVectorPair
;
725 mpControlVector
->append(aVectorPair
);
729 void insert(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rPoint
, sal_uInt32 nCount
)
733 mpBufferedData
.reset();
734 CoordinateData2D
aCoordinate(rPoint
);
735 maPoints
.insert(nIndex
, aCoordinate
, nCount
);
739 ControlVectorPair2D aVectorPair
;
740 mpControlVector
->insert(nIndex
, aVectorPair
, nCount
);
745 const basegfx::B2DVector
& getPrevControlVector(sal_uInt32 nIndex
) const
749 return mpControlVector
->getPrevVector(nIndex
);
753 return basegfx::B2DVector::getEmptyVector();
757 void setPrevControlVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
761 if(!rValue
.equalZero())
763 mpBufferedData
.reset();
764 mpControlVector
.reset( new ControlVectorArray2D(maPoints
.count()) );
765 mpControlVector
->setPrevVector(nIndex
, rValue
);
770 mpBufferedData
.reset();
771 mpControlVector
->setPrevVector(nIndex
, rValue
);
773 if(!mpControlVector
->isUsed())
774 mpControlVector
.reset();
778 const basegfx::B2DVector
& getNextControlVector(sal_uInt32 nIndex
) const
782 return mpControlVector
->getNextVector(nIndex
);
786 return basegfx::B2DVector::getEmptyVector();
790 void setNextControlVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
794 if(!rValue
.equalZero())
796 mpBufferedData
.reset();
797 mpControlVector
.reset( new ControlVectorArray2D(maPoints
.count()) );
798 mpControlVector
->setNextVector(nIndex
, rValue
);
803 mpBufferedData
.reset();
804 mpControlVector
->setNextVector(nIndex
, rValue
);
806 if(!mpControlVector
->isUsed())
807 mpControlVector
.reset();
811 bool areControlPointsUsed() const
813 return (mpControlVector
&& mpControlVector
->isUsed());
816 void resetControlVectors()
818 mpBufferedData
.reset();
819 mpControlVector
.reset();
822 void setControlVectors(sal_uInt32 nIndex
, const basegfx::B2DVector
& rPrev
, const basegfx::B2DVector
& rNext
)
824 setPrevControlVector(nIndex
, rPrev
);
825 setNextControlVector(nIndex
, rNext
);
828 void appendBezierSegment(const basegfx::B2DVector
& rNext
, const basegfx::B2DVector
& rPrev
, const basegfx::B2DPoint
& rPoint
)
830 mpBufferedData
.reset();
831 const sal_uInt32
nCount(maPoints
.count());
835 setNextControlVector(nCount
- 1, rNext
);
838 insert(nCount
, rPoint
, 1);
839 setPrevControlVector(nCount
, rPrev
);
842 void insert(sal_uInt32 nIndex
, const ImplB2DPolygon
& rSource
)
844 const sal_uInt32
nCount(rSource
.maPoints
.count());
848 mpBufferedData
.reset();
850 if(rSource
.mpControlVector
&& rSource
.mpControlVector
->isUsed() && !mpControlVector
)
852 mpControlVector
.reset( new ControlVectorArray2D(maPoints
.count()) );
855 maPoints
.insert(nIndex
, rSource
.maPoints
);
857 if(rSource
.mpControlVector
)
859 mpControlVector
->insert(nIndex
, *rSource
.mpControlVector
);
861 if(!mpControlVector
->isUsed())
862 mpControlVector
.reset();
864 else if(mpControlVector
)
866 ControlVectorPair2D aVectorPair
;
867 mpControlVector
->insert(nIndex
, aVectorPair
, nCount
);
872 void remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
876 mpBufferedData
.reset();
877 maPoints
.remove(nIndex
, nCount
);
881 mpControlVector
->remove(nIndex
, nCount
);
883 if(!mpControlVector
->isUsed())
884 mpControlVector
.reset();
891 if(maPoints
.count() > 1)
893 mpBufferedData
.reset();
896 maPoints
.flip(mbIsClosed
);
900 // flip control vector
901 mpControlVector
->flip(mbIsClosed
);
906 bool hasDoublePoints() const
910 // check for same start and end point
911 const sal_uInt32
nIndex(maPoints
.count() - 1);
913 if(maPoints
.getCoordinate(0) == maPoints
.getCoordinate(nIndex
))
917 if(mpControlVector
->getNextVector(nIndex
).equalZero() && mpControlVector
->getPrevVector(0).equalZero())
930 for(sal_uInt32
a(0); a
< maPoints
.count() - 1; a
++)
932 if(maPoints
.getCoordinate(a
) == maPoints
.getCoordinate(a
+ 1))
936 if(mpControlVector
->getNextVector(a
).equalZero() && mpControlVector
->getPrevVector(a
+ 1).equalZero())
951 void removeDoublePointsAtBeginEnd()
953 // Only remove DoublePoints at Begin and End when poly is closed
956 mpBufferedData
.reset();
966 if(maPoints
.count() > 1)
968 const sal_uInt32
nIndex(maPoints
.count() - 1);
970 if(maPoints
.getCoordinate(0) == maPoints
.getCoordinate(nIndex
))
974 if(mpControlVector
->getNextVector(nIndex
).equalZero() && mpControlVector
->getPrevVector(0).equalZero())
988 const sal_uInt32
nIndex(maPoints
.count() - 1);
990 if(mpControlVector
&& !mpControlVector
->getPrevVector(nIndex
).equalZero())
992 mpControlVector
->setPrevVector(0, mpControlVector
->getPrevVector(nIndex
));
1002 maPoints
.removeDoublePointsAtBeginEnd();
1007 void removeDoublePointsWholeTrack()
1009 mpBufferedData
.reset();
1013 sal_uInt32
nIndex(0);
1015 // test as long as there are at least two points and as long as the index
1016 // is smaller or equal second last point
1017 while((maPoints
.count() > 1) && (nIndex
<= maPoints
.count() - 2))
1019 bool bRemove(maPoints
.getCoordinate(nIndex
) == maPoints
.getCoordinate(nIndex
+ 1));
1025 if(!mpControlVector
->getNextVector(nIndex
).equalZero() || !mpControlVector
->getPrevVector(nIndex
+ 1).equalZero())
1034 if(mpControlVector
&& !mpControlVector
->getPrevVector(nIndex
).equalZero())
1036 mpControlVector
->setPrevVector(nIndex
+ 1, mpControlVector
->getPrevVector(nIndex
));
1039 // if next is same as index and the control vectors are unused, delete index
1044 // if different, step forward
1051 maPoints
.removeDoublePointsWholeTrack();
1055 void transform(const basegfx::B2DHomMatrix
& rMatrix
)
1057 mpBufferedData
.reset();
1061 for(sal_uInt32
a(0); a
< maPoints
.count(); a
++)
1063 basegfx::B2DPoint aCandidate
= maPoints
.getCoordinate(a
);
1065 if(mpControlVector
->isUsed())
1067 const basegfx::B2DVector
& rPrevVector(mpControlVector
->getPrevVector(a
));
1068 const basegfx::B2DVector
& rNextVector(mpControlVector
->getNextVector(a
));
1070 if(!rPrevVector
.equalZero())
1072 basegfx::B2DVector
aPrevVector(rMatrix
* rPrevVector
);
1073 mpControlVector
->setPrevVector(a
, aPrevVector
);
1076 if(!rNextVector
.equalZero())
1078 basegfx::B2DVector
aNextVector(rMatrix
* rNextVector
);
1079 mpControlVector
->setNextVector(a
, aNextVector
);
1083 aCandidate
*= rMatrix
;
1084 maPoints
.setCoordinate(a
, aCandidate
);
1087 if(!mpControlVector
->isUsed())
1088 mpControlVector
.reset();
1092 maPoints
.transform(rMatrix
);
1101 struct DefaultPolygon
: public rtl::Static
<B2DPolygon::ImplType
, DefaultPolygon
> {};
1104 B2DPolygon::B2DPolygon()
1105 : mpPolygon(DefaultPolygon::get())
1108 B2DPolygon::B2DPolygon(const B2DPolygon
& rPolygon
)
1109 : mpPolygon(rPolygon
.mpPolygon
)
1112 B2DPolygon::B2DPolygon(const B2DPolygon
& rPolygon
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
1113 : mpPolygon(ImplB2DPolygon(*rPolygon
.mpPolygon
, nIndex
, nCount
))
1115 // TODO(P2): one extra temporary here (cow_wrapper copies
1116 // given ImplB2DPolygon into its internal impl_t wrapper type)
1117 OSL_ENSURE(nIndex
+ nCount
<= rPolygon
.mpPolygon
->count(), "B2DPolygon constructor outside range (!)");
1120 B2DPolygon::~B2DPolygon()
1124 B2DPolygon
& B2DPolygon::operator=(const B2DPolygon
& rPolygon
)
1126 mpPolygon
= rPolygon
.mpPolygon
;
1130 void B2DPolygon::makeUnique()
1132 mpPolygon
.make_unique();
1135 bool B2DPolygon::operator==(const B2DPolygon
& rPolygon
) const
1137 if(mpPolygon
.same_object(rPolygon
.mpPolygon
))
1140 return ((*mpPolygon
) == (*rPolygon
.mpPolygon
));
1143 bool B2DPolygon::operator!=(const B2DPolygon
& rPolygon
) const
1145 return !(*this == rPolygon
);
1148 sal_uInt32
B2DPolygon::count() const
1150 return mpPolygon
->count();
1153 B2DPoint
B2DPolygon::getB2DPoint(sal_uInt32 nIndex
) const
1155 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1157 return mpPolygon
->getPoint(nIndex
);
1160 void B2DPolygon::setB2DPoint(sal_uInt32 nIndex
, const B2DPoint
& rValue
)
1162 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1164 if(mpPolygon
->getPoint(nIndex
) != rValue
)
1166 mpPolygon
->setPoint(nIndex
, rValue
);
1170 void B2DPolygon::reserve(sal_uInt32 nCount
)
1172 mpPolygon
->reserve(nCount
);
1175 void B2DPolygon::insert(sal_uInt32 nIndex
, const B2DPoint
& rPoint
, sal_uInt32 nCount
)
1177 OSL_ENSURE(nIndex
<= mpPolygon
->count(), "B2DPolygon Insert outside range (!)");
1181 mpPolygon
->insert(nIndex
, rPoint
, nCount
);
1185 void B2DPolygon::append(const B2DPoint
& rPoint
, sal_uInt32 nCount
)
1189 mpPolygon
->insert(mpPolygon
->count(), rPoint
, nCount
);
1193 void B2DPolygon::append(const B2DPoint
& rPoint
)
1195 mpPolygon
->append(rPoint
);
1198 B2DPoint
B2DPolygon::getPrevControlPoint(sal_uInt32 nIndex
) const
1200 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1202 if(mpPolygon
->areControlPointsUsed())
1204 return mpPolygon
->getPoint(nIndex
) + mpPolygon
->getPrevControlVector(nIndex
);
1208 return mpPolygon
->getPoint(nIndex
);
1212 B2DPoint
B2DPolygon::getNextControlPoint(sal_uInt32 nIndex
) const
1214 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1216 if(mpPolygon
->areControlPointsUsed())
1218 return mpPolygon
->getPoint(nIndex
) + mpPolygon
->getNextControlVector(nIndex
);
1222 return mpPolygon
->getPoint(nIndex
);
1226 void B2DPolygon::setPrevControlPoint(sal_uInt32 nIndex
, const B2DPoint
& rValue
)
1228 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1229 const basegfx::B2DVector
aNewVector(rValue
- mpPolygon
->getPoint(nIndex
));
1231 if(mpPolygon
->getPrevControlVector(nIndex
) != aNewVector
)
1233 mpPolygon
->setPrevControlVector(nIndex
, aNewVector
);
1237 void B2DPolygon::setNextControlPoint(sal_uInt32 nIndex
, const B2DPoint
& rValue
)
1239 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1240 const basegfx::B2DVector
aNewVector(rValue
- mpPolygon
->getPoint(nIndex
));
1242 if(mpPolygon
->getNextControlVector(nIndex
) != aNewVector
)
1244 mpPolygon
->setNextControlVector(nIndex
, aNewVector
);
1248 void B2DPolygon::setControlPoints(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rPrev
, const basegfx::B2DPoint
& rNext
)
1250 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1251 const B2DPoint
aPoint(mpPolygon
->getPoint(nIndex
));
1252 const basegfx::B2DVector
aNewPrev(rPrev
- aPoint
);
1253 const basegfx::B2DVector
aNewNext(rNext
- aPoint
);
1255 if(mpPolygon
->getPrevControlVector(nIndex
) != aNewPrev
|| mpPolygon
->getNextControlVector(nIndex
) != aNewNext
)
1257 mpPolygon
->setControlVectors(nIndex
, aNewPrev
, aNewNext
);
1261 void B2DPolygon::resetPrevControlPoint(sal_uInt32 nIndex
)
1263 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1265 if(mpPolygon
->areControlPointsUsed() && !mpPolygon
->getPrevControlVector(nIndex
).equalZero())
1267 mpPolygon
->setPrevControlVector(nIndex
, B2DVector::getEmptyVector());
1271 void B2DPolygon::resetNextControlPoint(sal_uInt32 nIndex
)
1273 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1275 if(mpPolygon
->areControlPointsUsed() && !mpPolygon
->getNextControlVector(nIndex
).equalZero())
1277 mpPolygon
->setNextControlVector(nIndex
, B2DVector::getEmptyVector());
1281 void B2DPolygon::resetControlPoints()
1283 if(mpPolygon
->areControlPointsUsed())
1285 mpPolygon
->resetControlVectors();
1289 void B2DPolygon::appendBezierSegment(
1290 const B2DPoint
& rNextControlPoint
,
1291 const B2DPoint
& rPrevControlPoint
,
1292 const B2DPoint
& rPoint
)
1294 const B2DVector
aNewNextVector(mpPolygon
->count() ? B2DVector(rNextControlPoint
- mpPolygon
->getPoint(mpPolygon
->count() - 1)) : B2DVector::getEmptyVector());
1295 const B2DVector
aNewPrevVector(rPrevControlPoint
- rPoint
);
1297 if(aNewNextVector
.equalZero() && aNewPrevVector
.equalZero())
1299 mpPolygon
->insert(mpPolygon
->count(), rPoint
, 1);
1303 mpPolygon
->appendBezierSegment(aNewNextVector
, aNewPrevVector
, rPoint
);
1307 bool B2DPolygon::areControlPointsUsed() const
1309 return mpPolygon
->areControlPointsUsed();
1312 bool B2DPolygon::isPrevControlPointUsed(sal_uInt32 nIndex
) const
1314 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1316 return (mpPolygon
->areControlPointsUsed() && !mpPolygon
->getPrevControlVector(nIndex
).equalZero());
1319 bool B2DPolygon::isNextControlPointUsed(sal_uInt32 nIndex
) const
1321 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1323 return (mpPolygon
->areControlPointsUsed() && !mpPolygon
->getNextControlVector(nIndex
).equalZero());
1326 B2VectorContinuity
B2DPolygon::getContinuityInPoint(sal_uInt32 nIndex
) const
1328 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1330 if(mpPolygon
->areControlPointsUsed())
1332 const B2DVector
& rPrev(mpPolygon
->getPrevControlVector(nIndex
));
1333 const B2DVector
& rNext(mpPolygon
->getNextControlVector(nIndex
));
1335 return getContinuity(rPrev
, rNext
);
1339 return CONTINUITY_NONE
;
1343 void B2DPolygon::getBezierSegment(sal_uInt32 nIndex
, B2DCubicBezier
& rTarget
) const
1345 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1346 const bool bNextIndexValidWithoutClose(nIndex
+ 1 < mpPolygon
->count());
1348 if(bNextIndexValidWithoutClose
|| mpPolygon
->isClosed())
1350 const sal_uInt32
nNextIndex(bNextIndexValidWithoutClose
? nIndex
+ 1 : 0);
1351 rTarget
.setStartPoint(mpPolygon
->getPoint(nIndex
));
1352 rTarget
.setEndPoint(mpPolygon
->getPoint(nNextIndex
));
1354 if(mpPolygon
->areControlPointsUsed())
1356 rTarget
.setControlPointA(rTarget
.getStartPoint() + mpPolygon
->getNextControlVector(nIndex
));
1357 rTarget
.setControlPointB(rTarget
.getEndPoint() + mpPolygon
->getPrevControlVector(nNextIndex
));
1361 // no bezier, reset control poins at rTarget
1362 rTarget
.setControlPointA(rTarget
.getStartPoint());
1363 rTarget
.setControlPointB(rTarget
.getEndPoint());
1368 // no valid edge at all, reset rTarget to current point
1369 const B2DPoint
aPoint(mpPolygon
->getPoint(nIndex
));
1370 rTarget
.setStartPoint(aPoint
);
1371 rTarget
.setEndPoint(aPoint
);
1372 rTarget
.setControlPointA(aPoint
);
1373 rTarget
.setControlPointB(aPoint
);
1377 B2DPolygon
B2DPolygon::getDefaultAdaptiveSubdivision() const
1379 return mpPolygon
->getDefaultAdaptiveSubdivision(*this);
1382 B2DRange
B2DPolygon::getB2DRange() const
1384 return mpPolygon
->getB2DRange(*this);
1387 void B2DPolygon::append(const B2DPolygon
& rPoly
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
1393 nCount
= rPoly
.count();
1396 if(0 == nIndex
&& nCount
== rPoly
.count())
1398 mpPolygon
->insert(mpPolygon
->count(), *rPoly
.mpPolygon
);
1402 OSL_ENSURE(nIndex
+ nCount
<= rPoly
.mpPolygon
->count(), "B2DPolygon Append outside range (!)");
1403 ImplB2DPolygon
aTempPoly(*rPoly
.mpPolygon
, nIndex
, nCount
);
1404 mpPolygon
->insert(mpPolygon
->count(), aTempPoly
);
1409 void B2DPolygon::remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
1411 OSL_ENSURE(nIndex
+ nCount
<= mpPolygon
->count(), "B2DPolygon Remove outside range (!)");
1415 mpPolygon
->remove(nIndex
, nCount
);
1419 void B2DPolygon::clear()
1421 mpPolygon
= DefaultPolygon::get();
1424 bool B2DPolygon::isClosed() const
1426 return mpPolygon
->isClosed();
1429 void B2DPolygon::setClosed(bool bNew
)
1431 if(isClosed() != bNew
)
1433 mpPolygon
->setClosed(bNew
);
1437 void B2DPolygon::flip()
1445 bool B2DPolygon::hasDoublePoints() const
1447 return (mpPolygon
->count() > 1 && mpPolygon
->hasDoublePoints());
1450 void B2DPolygon::removeDoublePoints()
1452 if(hasDoublePoints())
1454 mpPolygon
->removeDoublePointsAtBeginEnd();
1455 mpPolygon
->removeDoublePointsWholeTrack();
1459 void B2DPolygon::transform(const B2DHomMatrix
& rMatrix
)
1461 if(mpPolygon
->count() && !rMatrix
.isIdentity())
1463 mpPolygon
->transform(rMatrix
);
1467 } // end of namespace basegfx
1469 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */