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 <basegfx/polygon/b2dpolygontools.hxx>
27 #include <basegfx/utils/systemdependentdata.hxx>
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 CoordinateDataArray2D(const CoordinateDataArray2D
& rOriginal
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
66 : maVector(rOriginal
.maVector
.begin() + nIndex
, rOriginal
.maVector
.begin() + (nIndex
+ nCount
))
70 sal_uInt32
count() const
72 return maVector
.size();
75 bool operator==(const CoordinateDataArray2D
& rCandidate
) const
77 return (maVector
== rCandidate
.maVector
);
80 const basegfx::B2DPoint
& getCoordinate(sal_uInt32 nIndex
) const
82 return maVector
[nIndex
];
85 void setCoordinate(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rValue
)
87 maVector
[nIndex
] = rValue
;
90 void reserve(sal_uInt32 nCount
)
92 maVector
.reserve(nCount
);
95 void append(const CoordinateData2D
& rValue
)
97 maVector
.push_back(rValue
);
100 void insert(sal_uInt32 nIndex
, const CoordinateData2D
& rValue
, sal_uInt32 nCount
)
104 // add nCount copies of rValue
105 CoordinateData2DVector::iterator
aIndex(maVector
.begin());
107 maVector
.insert(aIndex
, nCount
, rValue
);
111 void insert(sal_uInt32 nIndex
, const CoordinateDataArray2D
& rSource
)
113 const sal_uInt32
nCount(rSource
.maVector
.size());
118 CoordinateData2DVector::iterator
aIndex(maVector
.begin());
120 CoordinateData2DVector::const_iterator
aStart(rSource
.maVector
.begin());
121 CoordinateData2DVector::const_iterator
aEnd(rSource
.maVector
.end());
122 maVector
.insert(aIndex
, aStart
, aEnd
);
126 void remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
131 CoordinateData2DVector::iterator
aStart(maVector
.begin());
133 const CoordinateData2DVector::iterator
aEnd(aStart
+ nCount
);
134 maVector
.erase(aStart
, aEnd
);
138 void flip(bool bIsClosed
)
140 if(maVector
.size() > 1)
142 // to keep the same point at index 0, just flip all points except the
143 // first one when closed
144 const sal_uInt32
nHalfSize(bIsClosed
? (maVector
.size() - 1) >> 1 : maVector
.size() >> 1);
145 CoordinateData2DVector::iterator
aStart(bIsClosed
? maVector
.begin() + 1 : maVector
.begin());
146 CoordinateData2DVector::iterator
aEnd(maVector
.end() - 1);
148 for(sal_uInt32
a(0); a
< nHalfSize
; a
++)
150 std::swap(*aStart
, *aEnd
);
157 void removeDoublePointsAtBeginEnd()
159 // remove from end as long as there are at least two points
160 // and begin/end are equal
161 while((maVector
.size() > 1) && (maVector
[0] == maVector
[maVector
.size() - 1]))
167 void removeDoublePointsWholeTrack()
169 sal_uInt32
nIndex(0);
171 // test as long as there are at least two points and as long as the index
172 // is smaller or equal second last point
173 while((maVector
.size() > 1) && (nIndex
<= maVector
.size() - 2))
175 if(maVector
[nIndex
] == maVector
[nIndex
+ 1])
177 // if next is same as index, delete next
178 maVector
.erase(maVector
.begin() + (nIndex
+ 1));
182 // if different, step forward
188 void transform(const basegfx::B2DHomMatrix
& rMatrix
)
190 for (auto & elem
: maVector
)
192 elem
.transform(rMatrix
);
197 class ControlVectorPair2D
199 basegfx::B2DVector maPrevVector
;
200 basegfx::B2DVector maNextVector
;
203 explicit ControlVectorPair2D() {}
205 const basegfx::B2DVector
& getPrevVector() const
210 void setPrevVector(const basegfx::B2DVector
& rValue
)
212 if(rValue
!= maPrevVector
)
213 maPrevVector
= rValue
;
216 const basegfx::B2DVector
& getNextVector() const
221 void setNextVector(const basegfx::B2DVector
& rValue
)
223 if(rValue
!= maNextVector
)
224 maNextVector
= rValue
;
227 bool operator==(const ControlVectorPair2D
& rData
) const
229 return (maPrevVector
== rData
.getPrevVector() && maNextVector
== rData
.getNextVector());
234 std::swap(maPrevVector
, maNextVector
);
238 class ControlVectorArray2D
240 typedef std::vector
< ControlVectorPair2D
> ControlVectorPair2DVector
;
242 ControlVectorPair2DVector maVector
;
243 sal_uInt32 mnUsedVectors
;
246 explicit ControlVectorArray2D(sal_uInt32 nCount
)
251 ControlVectorArray2D(const ControlVectorArray2D
& rOriginal
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
255 ControlVectorPair2DVector::const_iterator
aStart(rOriginal
.maVector
.begin());
257 ControlVectorPair2DVector::const_iterator
aEnd(aStart
);
259 maVector
.reserve(nCount
);
261 for(; aStart
!= aEnd
; ++aStart
)
263 if(!aStart
->getPrevVector().equalZero())
266 if(!aStart
->getNextVector().equalZero())
269 maVector
.push_back(*aStart
);
273 bool operator==(const ControlVectorArray2D
& rCandidate
) const
275 return (maVector
== rCandidate
.maVector
);
280 return (mnUsedVectors
!= 0);
283 const basegfx::B2DVector
& getPrevVector(sal_uInt32 nIndex
) const
285 return maVector
[nIndex
].getPrevVector();
288 void setPrevVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
290 bool bWasUsed(mnUsedVectors
&& !maVector
[nIndex
].getPrevVector().equalZero());
291 bool bIsUsed(!rValue
.equalZero());
297 maVector
[nIndex
].setPrevVector(rValue
);
301 maVector
[nIndex
].setPrevVector(basegfx::B2DVector::getEmptyVector());
309 maVector
[nIndex
].setPrevVector(rValue
);
315 const basegfx::B2DVector
& getNextVector(sal_uInt32 nIndex
) const
317 return maVector
[nIndex
].getNextVector();
320 void setNextVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
322 bool bWasUsed(mnUsedVectors
&& !maVector
[nIndex
].getNextVector().equalZero());
323 bool bIsUsed(!rValue
.equalZero());
329 maVector
[nIndex
].setNextVector(rValue
);
333 maVector
[nIndex
].setNextVector(basegfx::B2DVector::getEmptyVector());
341 maVector
[nIndex
].setNextVector(rValue
);
347 void append(const ControlVectorPair2D
& rValue
)
349 maVector
.push_back(rValue
);
351 if(!rValue
.getPrevVector().equalZero())
354 if(!rValue
.getNextVector().equalZero())
358 void insert(sal_uInt32 nIndex
, const ControlVectorPair2D
& rValue
, sal_uInt32 nCount
)
362 // add nCount copies of rValue
363 ControlVectorPair2DVector::iterator
aIndex(maVector
.begin());
365 maVector
.insert(aIndex
, nCount
, rValue
);
367 if(!rValue
.getPrevVector().equalZero())
368 mnUsedVectors
+= nCount
;
370 if(!rValue
.getNextVector().equalZero())
371 mnUsedVectors
+= nCount
;
375 void insert(sal_uInt32 nIndex
, const ControlVectorArray2D
& rSource
)
377 const sal_uInt32
nCount(rSource
.maVector
.size());
382 ControlVectorPair2DVector::iterator
aIndex(maVector
.begin());
384 ControlVectorPair2DVector::const_iterator
aStart(rSource
.maVector
.begin());
385 ControlVectorPair2DVector::const_iterator
aEnd(rSource
.maVector
.end());
386 maVector
.insert(aIndex
, aStart
, aEnd
);
388 for(; aStart
!= aEnd
; ++aStart
)
390 if(!aStart
->getPrevVector().equalZero())
393 if(!aStart
->getNextVector().equalZero())
399 void remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
403 const ControlVectorPair2DVector::iterator
aDeleteStart(maVector
.begin() + nIndex
);
404 const ControlVectorPair2DVector::iterator
aDeleteEnd(aDeleteStart
+ nCount
);
405 ControlVectorPair2DVector::const_iterator
aStart(aDeleteStart
);
407 for(; mnUsedVectors
&& aStart
!= aDeleteEnd
; ++aStart
)
409 if(!aStart
->getPrevVector().equalZero())
412 if(mnUsedVectors
&& !aStart
->getNextVector().equalZero())
417 maVector
.erase(aDeleteStart
, aDeleteEnd
);
421 void flip(bool bIsClosed
)
423 if(maVector
.size() > 1)
425 // to keep the same point at index 0, just flip all points except the
426 // first one when closed
427 const sal_uInt32
nHalfSize(bIsClosed
? (maVector
.size() - 1) >> 1 : maVector
.size() >> 1);
428 ControlVectorPair2DVector::iterator
aStart(bIsClosed
? maVector
.begin() + 1 : maVector
.begin());
429 ControlVectorPair2DVector::iterator
aEnd(maVector
.end() - 1);
431 for(sal_uInt32
a(0); a
< nHalfSize
; a
++)
433 // swap Prev and Next
438 std::swap(*aStart
, *aEnd
);
446 // swap Prev and Next at middle element (if exists)
452 // swap Prev and Next at start element
453 maVector
.begin()->flip();
459 class ImplBufferedData
: public basegfx::SystemDependentDataHolder
462 // Possibility to hold the last subdivision
463 std::unique_ptr
< basegfx::B2DPolygon
> mpDefaultSubdivision
;
465 // Possibility to hold the last B2DRange calculation
466 std::unique_ptr
< basegfx::B2DRange
> mpB2DRange
;
470 : basegfx::SystemDependentDataHolder(),
471 mpDefaultSubdivision(),
476 const basegfx::B2DPolygon
& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon
& rSource
) const
478 if(!mpDefaultSubdivision
)
480 const_cast< ImplBufferedData
* >(this)->mpDefaultSubdivision
.reset(new basegfx::B2DPolygon(basegfx::utils::adaptiveSubdivideByAngle(rSource
)));
483 return *mpDefaultSubdivision
;
486 const basegfx::B2DRange
& getB2DRange(const basegfx::B2DPolygon
& rSource
) const
490 basegfx::B2DRange aNewRange
;
491 const sal_uInt32
nPointCount(rSource
.count());
495 for(sal_uInt32
a(0); a
< nPointCount
; a
++)
497 aNewRange
.expand(rSource
.getB2DPoint(a
));
500 if(rSource
.areControlPointsUsed())
502 const sal_uInt32
nEdgeCount(rSource
.isClosed() ? nPointCount
: nPointCount
- 1);
506 basegfx::B2DCubicBezier aEdge
;
507 aEdge
.setStartPoint(rSource
.getB2DPoint(0));
509 for(sal_uInt32
b(0); b
< nEdgeCount
; b
++)
511 const sal_uInt32
nNextIndex((b
+ 1) % nPointCount
);
512 aEdge
.setControlPointA(rSource
.getNextControlPoint(b
));
513 aEdge
.setControlPointB(rSource
.getPrevControlPoint(nNextIndex
));
514 aEdge
.setEndPoint(rSource
.getB2DPoint(nNextIndex
));
518 const basegfx::B2DRange
aBezierRangeWithControlPoints(aEdge
.getRange());
520 if(!aNewRange
.isInside(aBezierRangeWithControlPoints
))
522 // the range with control points of the current edge is not completely
523 // inside the current range without control points. Expand current range by
524 // subdividing the bezier segment.
525 // Ideal here is a subdivision at the extreme values, so use
526 // getAllExtremumPositions to get all extremas in one run
527 std::vector
< double > aExtremas
;
529 aExtremas
.reserve(4);
530 aEdge
.getAllExtremumPositions(aExtremas
);
532 const sal_uInt32
nExtremaCount(aExtremas
.size());
534 for(sal_uInt32
c(0); c
< nExtremaCount
; c
++)
536 aNewRange
.expand(aEdge
.interpolatePoint(aExtremas
[c
]));
542 aEdge
.setStartPoint(aEdge
.getEndPoint());
548 const_cast< ImplBufferedData
* >(this)->mpB2DRange
.reset(new basegfx::B2DRange(aNewRange
));
558 // The point vector. This vector exists always and defines the
560 CoordinateDataArray2D maPoints
;
562 // The control point vectors. This vectors are created on demand
564 std::unique_ptr
< ControlVectorArray2D
> mpControlVector
;
566 // buffered data for e.g. default subdivision and range
567 std::unique_ptr
< ImplBufferedData
> mpBufferedData
;
569 // flag which decides if this polygon is opened or closed
573 const basegfx::B2DPolygon
& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon
& rSource
) const
575 if(!mpControlVector
|| !mpControlVector
->isUsed())
582 const_cast< ImplB2DPolygon
* >(this)->mpBufferedData
.reset(new ImplBufferedData
);
585 return mpBufferedData
->getDefaultAdaptiveSubdivision(rSource
);
588 const basegfx::B2DRange
& getB2DRange(const basegfx::B2DPolygon
& rSource
) const
592 const_cast< ImplB2DPolygon
* >(this)->mpBufferedData
.reset(new ImplBufferedData
);
595 return mpBufferedData
->getB2DRange(rSource
);
605 ImplB2DPolygon(const ImplB2DPolygon
& rToBeCopied
)
606 : maPoints(rToBeCopied
.maPoints
),
609 mbIsClosed(rToBeCopied
.mbIsClosed
)
611 // complete initialization using copy
612 if(rToBeCopied
.mpControlVector
&& rToBeCopied
.mpControlVector
->isUsed())
614 mpControlVector
.reset( new ControlVectorArray2D(*rToBeCopied
.mpControlVector
) );
618 ImplB2DPolygon(const ImplB2DPolygon
& rToBeCopied
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
619 : maPoints(rToBeCopied
.maPoints
, nIndex
, nCount
),
622 mbIsClosed(rToBeCopied
.mbIsClosed
)
624 // complete initialization using partly copy
625 if(rToBeCopied
.mpControlVector
&& rToBeCopied
.mpControlVector
->isUsed())
627 mpControlVector
.reset( new ControlVectorArray2D(*rToBeCopied
.mpControlVector
, nIndex
, nCount
) );
629 if(!mpControlVector
->isUsed())
630 mpControlVector
.reset();
634 ImplB2DPolygon
& operator=(const ImplB2DPolygon
& rOther
)
638 mpControlVector
.reset();
639 mpBufferedData
.reset();
640 maPoints
= rOther
.maPoints
;
641 mbIsClosed
= rOther
.mbIsClosed
;
642 if (rOther
.mpControlVector
&& rOther
.mpControlVector
->isUsed())
644 mpControlVector
.reset( new ControlVectorArray2D(*rOther
.mpControlVector
) );
646 if(!mpControlVector
->isUsed())
647 mpControlVector
.reset();
653 sal_uInt32
count() const
655 return maPoints
.count();
658 bool isClosed() const
663 void setClosed(bool bNew
)
665 if(bNew
!= mbIsClosed
)
667 mpBufferedData
.reset();
672 bool operator==(const ImplB2DPolygon
& rCandidate
) const
674 if(mbIsClosed
== rCandidate
.mbIsClosed
)
676 if(maPoints
== rCandidate
.maPoints
)
678 bool bControlVectorsAreEqual(true);
682 if(rCandidate
.mpControlVector
)
684 bControlVectorsAreEqual
= ((*mpControlVector
) == (*rCandidate
.mpControlVector
));
688 // candidate has no control vector, so it's assumed all unused.
689 bControlVectorsAreEqual
= !mpControlVector
->isUsed();
694 if(rCandidate
.mpControlVector
)
696 // we have no control vector, so it's assumed all unused.
697 bControlVectorsAreEqual
= !rCandidate
.mpControlVector
->isUsed();
701 if(bControlVectorsAreEqual
)
711 const basegfx::B2DPoint
& getPoint(sal_uInt32 nIndex
) const
713 return maPoints
.getCoordinate(nIndex
);
716 void setPoint(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rValue
)
718 mpBufferedData
.reset();
719 maPoints
.setCoordinate(nIndex
, rValue
);
722 void reserve(sal_uInt32 nCount
)
724 maPoints
.reserve(nCount
);
727 void append(const basegfx::B2DPoint
& rPoint
)
729 mpBufferedData
.reset(); // TODO: is this needed?
730 const CoordinateData2D
aCoordinate(rPoint
);
731 maPoints
.append(aCoordinate
);
735 const ControlVectorPair2D aVectorPair
;
736 mpControlVector
->append(aVectorPair
);
740 void insert(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rPoint
, sal_uInt32 nCount
)
744 mpBufferedData
.reset();
745 CoordinateData2D
aCoordinate(rPoint
);
746 maPoints
.insert(nIndex
, aCoordinate
, nCount
);
750 ControlVectorPair2D aVectorPair
;
751 mpControlVector
->insert(nIndex
, aVectorPair
, nCount
);
756 const basegfx::B2DVector
& getPrevControlVector(sal_uInt32 nIndex
) const
760 return mpControlVector
->getPrevVector(nIndex
);
764 return basegfx::B2DVector::getEmptyVector();
768 void setPrevControlVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
772 if(!rValue
.equalZero())
774 mpBufferedData
.reset();
775 mpControlVector
.reset( new ControlVectorArray2D(maPoints
.count()) );
776 mpControlVector
->setPrevVector(nIndex
, rValue
);
781 mpBufferedData
.reset();
782 mpControlVector
->setPrevVector(nIndex
, rValue
);
784 if(!mpControlVector
->isUsed())
785 mpControlVector
.reset();
789 const basegfx::B2DVector
& getNextControlVector(sal_uInt32 nIndex
) const
793 return mpControlVector
->getNextVector(nIndex
);
797 return basegfx::B2DVector::getEmptyVector();
801 void setNextControlVector(sal_uInt32 nIndex
, const basegfx::B2DVector
& rValue
)
805 if(!rValue
.equalZero())
807 mpBufferedData
.reset();
808 mpControlVector
.reset( new ControlVectorArray2D(maPoints
.count()) );
809 mpControlVector
->setNextVector(nIndex
, rValue
);
814 mpBufferedData
.reset();
815 mpControlVector
->setNextVector(nIndex
, rValue
);
817 if(!mpControlVector
->isUsed())
818 mpControlVector
.reset();
822 bool areControlPointsUsed() const
824 return (mpControlVector
&& mpControlVector
->isUsed());
827 void resetControlVectors()
829 mpBufferedData
.reset();
830 mpControlVector
.reset();
833 void setControlVectors(sal_uInt32 nIndex
, const basegfx::B2DVector
& rPrev
, const basegfx::B2DVector
& rNext
)
835 setPrevControlVector(nIndex
, rPrev
);
836 setNextControlVector(nIndex
, rNext
);
839 void appendBezierSegment(const basegfx::B2DVector
& rNext
, const basegfx::B2DVector
& rPrev
, const basegfx::B2DPoint
& rPoint
)
841 mpBufferedData
.reset();
842 const sal_uInt32
nCount(maPoints
.count());
846 setNextControlVector(nCount
- 1, rNext
);
849 insert(nCount
, rPoint
, 1);
850 setPrevControlVector(nCount
, rPrev
);
853 void insert(sal_uInt32 nIndex
, const ImplB2DPolygon
& rSource
)
855 const sal_uInt32
nCount(rSource
.maPoints
.count());
859 mpBufferedData
.reset();
861 if(rSource
.mpControlVector
&& rSource
.mpControlVector
->isUsed() && !mpControlVector
)
863 mpControlVector
.reset( new ControlVectorArray2D(maPoints
.count()) );
866 maPoints
.insert(nIndex
, rSource
.maPoints
);
868 if(rSource
.mpControlVector
)
870 mpControlVector
->insert(nIndex
, *rSource
.mpControlVector
);
872 if(!mpControlVector
->isUsed())
873 mpControlVector
.reset();
875 else if(mpControlVector
)
877 ControlVectorPair2D aVectorPair
;
878 mpControlVector
->insert(nIndex
, aVectorPair
, nCount
);
883 void remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
887 mpBufferedData
.reset();
888 maPoints
.remove(nIndex
, nCount
);
892 mpControlVector
->remove(nIndex
, nCount
);
894 if(!mpControlVector
->isUsed())
895 mpControlVector
.reset();
902 if(maPoints
.count() > 1)
904 mpBufferedData
.reset();
907 maPoints
.flip(mbIsClosed
);
911 // flip control vector
912 mpControlVector
->flip(mbIsClosed
);
917 bool hasDoublePoints() const
921 // check for same start and end point
922 const sal_uInt32
nIndex(maPoints
.count() - 1);
924 if(maPoints
.getCoordinate(0) == maPoints
.getCoordinate(nIndex
))
928 if(mpControlVector
->getNextVector(nIndex
).equalZero() && mpControlVector
->getPrevVector(0).equalZero())
941 for(sal_uInt32
a(0); a
< maPoints
.count() - 1; a
++)
943 if(maPoints
.getCoordinate(a
) == maPoints
.getCoordinate(a
+ 1))
947 if(mpControlVector
->getNextVector(a
).equalZero() && mpControlVector
->getPrevVector(a
+ 1).equalZero())
962 void removeDoublePointsAtBeginEnd()
964 // Only remove DoublePoints at Begin and End when poly is closed
967 mpBufferedData
.reset();
977 if(maPoints
.count() > 1)
979 const sal_uInt32
nIndex(maPoints
.count() - 1);
981 if(maPoints
.getCoordinate(0) == maPoints
.getCoordinate(nIndex
))
985 if(mpControlVector
->getNextVector(nIndex
).equalZero() && mpControlVector
->getPrevVector(0).equalZero())
999 const sal_uInt32
nIndex(maPoints
.count() - 1);
1001 if(mpControlVector
&& !mpControlVector
->getPrevVector(nIndex
).equalZero())
1003 mpControlVector
->setPrevVector(0, mpControlVector
->getPrevVector(nIndex
));
1013 maPoints
.removeDoublePointsAtBeginEnd();
1018 void removeDoublePointsWholeTrack()
1020 mpBufferedData
.reset();
1024 sal_uInt32
nIndex(0);
1026 // test as long as there are at least two points and as long as the index
1027 // is smaller or equal second last point
1028 while((maPoints
.count() > 1) && (nIndex
<= maPoints
.count() - 2))
1030 bool bRemove(maPoints
.getCoordinate(nIndex
) == maPoints
.getCoordinate(nIndex
+ 1));
1032 if(bRemove
&& mpControlVector
)
1034 if(!mpControlVector
->getNextVector(nIndex
).equalZero() || !mpControlVector
->getPrevVector(nIndex
+ 1).equalZero())
1042 if(mpControlVector
&& !mpControlVector
->getPrevVector(nIndex
).equalZero())
1044 mpControlVector
->setPrevVector(nIndex
+ 1, mpControlVector
->getPrevVector(nIndex
));
1047 // if next is same as index and the control vectors are unused, delete index
1052 // if different, step forward
1059 maPoints
.removeDoublePointsWholeTrack();
1063 void transform(const basegfx::B2DHomMatrix
& rMatrix
)
1065 mpBufferedData
.reset();
1069 for(sal_uInt32
a(0); a
< maPoints
.count(); a
++)
1071 basegfx::B2DPoint aCandidate
= maPoints
.getCoordinate(a
);
1073 if(mpControlVector
->isUsed())
1075 const basegfx::B2DVector
& rPrevVector(mpControlVector
->getPrevVector(a
));
1076 const basegfx::B2DVector
& rNextVector(mpControlVector
->getNextVector(a
));
1078 if(!rPrevVector
.equalZero())
1080 basegfx::B2DVector
aPrevVector(rMatrix
* rPrevVector
);
1081 mpControlVector
->setPrevVector(a
, aPrevVector
);
1084 if(!rNextVector
.equalZero())
1086 basegfx::B2DVector
aNextVector(rMatrix
* rNextVector
);
1087 mpControlVector
->setNextVector(a
, aNextVector
);
1091 aCandidate
*= rMatrix
;
1092 maPoints
.setCoordinate(a
, aCandidate
);
1095 if(!mpControlVector
->isUsed())
1096 mpControlVector
.reset();
1100 maPoints
.transform(rMatrix
);
1104 void addOrReplaceSystemDependentData(basegfx::SystemDependentData_SharedPtr
& rData
)
1108 mpBufferedData
.reset(new ImplBufferedData
);
1111 mpBufferedData
->addOrReplaceSystemDependentData(rData
);
1114 basegfx::SystemDependentData_SharedPtr
getSystemDependentData(size_t hash_code
) const
1118 return mpBufferedData
->getSystemDependentData(hash_code
);
1121 return basegfx::SystemDependentData_SharedPtr();
1127 B2DPolygon::B2DPolygon() = default;
1129 B2DPolygon::B2DPolygon(std::initializer_list
<basegfx::B2DPoint
> aPoints
)
1132 for (const basegfx::B2DPoint
& rPoint
: aPoints
)
1138 B2DPolygon::B2DPolygon(const B2DPolygon
&) = default;
1140 B2DPolygon::B2DPolygon(B2DPolygon
&&) = default;
1142 B2DPolygon::B2DPolygon(const B2DPolygon
& rPolygon
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
1143 : mpPolygon(ImplB2DPolygon(*rPolygon
.mpPolygon
, nIndex
, nCount
))
1145 // TODO(P2): one extra temporary here (cow_wrapper copies
1146 // given ImplB2DPolygon into its internal impl_t wrapper type)
1147 OSL_ENSURE(nIndex
+ nCount
<= rPolygon
.mpPolygon
->count(), "B2DPolygon constructor outside range (!)");
1150 B2DPolygon::~B2DPolygon() = default;
1152 B2DPolygon
& B2DPolygon::operator=(const B2DPolygon
&) = default;
1154 B2DPolygon
& B2DPolygon::operator=(B2DPolygon
&&) = default;
1156 void B2DPolygon::makeUnique()
1158 mpPolygon
.make_unique();
1161 bool B2DPolygon::operator==(const B2DPolygon
& rPolygon
) const
1163 if(mpPolygon
.same_object(rPolygon
.mpPolygon
))
1166 return ((*mpPolygon
) == (*rPolygon
.mpPolygon
));
1169 bool B2DPolygon::operator!=(const B2DPolygon
& rPolygon
) const
1171 return !(*this == rPolygon
);
1174 sal_uInt32
B2DPolygon::count() const
1176 return mpPolygon
->count();
1179 B2DPoint
const & B2DPolygon::getB2DPoint(sal_uInt32 nIndex
) const
1181 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1183 return mpPolygon
->getPoint(nIndex
);
1186 void B2DPolygon::setB2DPoint(sal_uInt32 nIndex
, const B2DPoint
& rValue
)
1188 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1190 if(mpPolygon
->getPoint(nIndex
) != rValue
)
1192 mpPolygon
->setPoint(nIndex
, rValue
);
1196 void B2DPolygon::reserve(sal_uInt32 nCount
)
1198 mpPolygon
->reserve(nCount
);
1201 void B2DPolygon::insert(sal_uInt32 nIndex
, const B2DPoint
& rPoint
, sal_uInt32 nCount
)
1203 OSL_ENSURE(nIndex
<= mpPolygon
->count(), "B2DPolygon Insert outside range (!)");
1207 mpPolygon
->insert(nIndex
, rPoint
, nCount
);
1211 void B2DPolygon::append(const B2DPoint
& rPoint
, sal_uInt32 nCount
)
1215 mpPolygon
->insert(mpPolygon
->count(), rPoint
, nCount
);
1219 void B2DPolygon::append(const B2DPoint
& rPoint
)
1221 mpPolygon
->append(rPoint
);
1224 B2DPoint
B2DPolygon::getPrevControlPoint(sal_uInt32 nIndex
) const
1226 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1228 if(mpPolygon
->areControlPointsUsed())
1230 return mpPolygon
->getPoint(nIndex
) + mpPolygon
->getPrevControlVector(nIndex
);
1234 return mpPolygon
->getPoint(nIndex
);
1238 B2DPoint
B2DPolygon::getNextControlPoint(sal_uInt32 nIndex
) const
1240 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1242 if(mpPolygon
->areControlPointsUsed())
1244 return mpPolygon
->getPoint(nIndex
) + mpPolygon
->getNextControlVector(nIndex
);
1248 return mpPolygon
->getPoint(nIndex
);
1252 void B2DPolygon::setPrevControlPoint(sal_uInt32 nIndex
, const B2DPoint
& rValue
)
1254 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1255 const basegfx::B2DVector
aNewVector(rValue
- mpPolygon
->getPoint(nIndex
));
1257 if(mpPolygon
->getPrevControlVector(nIndex
) != aNewVector
)
1259 mpPolygon
->setPrevControlVector(nIndex
, aNewVector
);
1263 void B2DPolygon::setNextControlPoint(sal_uInt32 nIndex
, const B2DPoint
& rValue
)
1265 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1266 const basegfx::B2DVector
aNewVector(rValue
- mpPolygon
->getPoint(nIndex
));
1268 if(mpPolygon
->getNextControlVector(nIndex
) != aNewVector
)
1270 mpPolygon
->setNextControlVector(nIndex
, aNewVector
);
1274 void B2DPolygon::setControlPoints(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rPrev
, const basegfx::B2DPoint
& rNext
)
1276 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1277 const B2DPoint
aPoint(mpPolygon
->getPoint(nIndex
));
1278 const basegfx::B2DVector
aNewPrev(rPrev
- aPoint
);
1279 const basegfx::B2DVector
aNewNext(rNext
- aPoint
);
1281 if(mpPolygon
->getPrevControlVector(nIndex
) != aNewPrev
|| mpPolygon
->getNextControlVector(nIndex
) != aNewNext
)
1283 mpPolygon
->setControlVectors(nIndex
, aNewPrev
, aNewNext
);
1287 void B2DPolygon::resetPrevControlPoint(sal_uInt32 nIndex
)
1289 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1291 if(mpPolygon
->areControlPointsUsed() && !mpPolygon
->getPrevControlVector(nIndex
).equalZero())
1293 mpPolygon
->setPrevControlVector(nIndex
, B2DVector::getEmptyVector());
1297 void B2DPolygon::resetNextControlPoint(sal_uInt32 nIndex
)
1299 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1301 if(mpPolygon
->areControlPointsUsed() && !mpPolygon
->getNextControlVector(nIndex
).equalZero())
1303 mpPolygon
->setNextControlVector(nIndex
, B2DVector::getEmptyVector());
1307 void B2DPolygon::resetControlPoints()
1309 if(mpPolygon
->areControlPointsUsed())
1311 mpPolygon
->resetControlVectors();
1315 void B2DPolygon::appendBezierSegment(
1316 const B2DPoint
& rNextControlPoint
,
1317 const B2DPoint
& rPrevControlPoint
,
1318 const B2DPoint
& rPoint
)
1320 const B2DVector
aNewNextVector(mpPolygon
->count() ? B2DVector(rNextControlPoint
- mpPolygon
->getPoint(mpPolygon
->count() - 1)) : B2DVector::getEmptyVector());
1321 const B2DVector
aNewPrevVector(rPrevControlPoint
- rPoint
);
1323 if(aNewNextVector
.equalZero() && aNewPrevVector
.equalZero())
1325 mpPolygon
->insert(mpPolygon
->count(), rPoint
, 1);
1329 mpPolygon
->appendBezierSegment(aNewNextVector
, aNewPrevVector
, rPoint
);
1333 void B2DPolygon::appendQuadraticBezierSegment(const B2DPoint
& rControlPoint
, const B2DPoint
& rPoint
)
1335 if (mpPolygon
->count() == 0)
1337 mpPolygon
->append(rPoint
);
1338 const double nX((rControlPoint
.getX() * 2.0 + rPoint
.getX()) / 3.0);
1339 const double nY((rControlPoint
.getY() * 2.0 + rPoint
.getY()) / 3.0);
1340 setPrevControlPoint(0, B2DPoint(nX
, nY
));
1344 const B2DPoint
aPreviousPoint(mpPolygon
->getPoint(mpPolygon
->count() - 1));
1346 const double nX1((rControlPoint
.getX() * 2.0 + aPreviousPoint
.getX()) / 3.0);
1347 const double nY1((rControlPoint
.getY() * 2.0 + aPreviousPoint
.getY()) / 3.0);
1348 const double nX2((rControlPoint
.getX() * 2.0 + rPoint
.getX()) / 3.0);
1349 const double nY2((rControlPoint
.getY() * 2.0 + rPoint
.getY()) / 3.0);
1351 appendBezierSegment(B2DPoint(nX1
, nY1
), B2DPoint(nX2
, nY2
), rPoint
);
1355 bool B2DPolygon::areControlPointsUsed() const
1357 return mpPolygon
->areControlPointsUsed();
1360 bool B2DPolygon::isPrevControlPointUsed(sal_uInt32 nIndex
) const
1362 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1364 return (mpPolygon
->areControlPointsUsed() && !mpPolygon
->getPrevControlVector(nIndex
).equalZero());
1367 bool B2DPolygon::isNextControlPointUsed(sal_uInt32 nIndex
) const
1369 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1371 return (mpPolygon
->areControlPointsUsed() && !mpPolygon
->getNextControlVector(nIndex
).equalZero());
1374 B2VectorContinuity
B2DPolygon::getContinuityInPoint(sal_uInt32 nIndex
) const
1376 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1378 if(mpPolygon
->areControlPointsUsed())
1380 const B2DVector
& rPrev(mpPolygon
->getPrevControlVector(nIndex
));
1381 const B2DVector
& rNext(mpPolygon
->getNextControlVector(nIndex
));
1383 return getContinuity(rPrev
, rNext
);
1387 return B2VectorContinuity::NONE
;
1391 void B2DPolygon::getBezierSegment(sal_uInt32 nIndex
, B2DCubicBezier
& rTarget
) const
1393 OSL_ENSURE(nIndex
< mpPolygon
->count(), "B2DPolygon access outside range (!)");
1394 const bool bNextIndexValidWithoutClose(nIndex
+ 1 < mpPolygon
->count());
1396 if(bNextIndexValidWithoutClose
|| mpPolygon
->isClosed())
1398 const sal_uInt32
nNextIndex(bNextIndexValidWithoutClose
? nIndex
+ 1 : 0);
1399 rTarget
.setStartPoint(mpPolygon
->getPoint(nIndex
));
1400 rTarget
.setEndPoint(mpPolygon
->getPoint(nNextIndex
));
1402 if(mpPolygon
->areControlPointsUsed())
1404 rTarget
.setControlPointA(rTarget
.getStartPoint() + mpPolygon
->getNextControlVector(nIndex
));
1405 rTarget
.setControlPointB(rTarget
.getEndPoint() + mpPolygon
->getPrevControlVector(nNextIndex
));
1409 // no bezier, reset control points at rTarget
1410 rTarget
.setControlPointA(rTarget
.getStartPoint());
1411 rTarget
.setControlPointB(rTarget
.getEndPoint());
1416 // no valid edge at all, reset rTarget to current point
1417 const B2DPoint
aPoint(mpPolygon
->getPoint(nIndex
));
1418 rTarget
.setStartPoint(aPoint
);
1419 rTarget
.setEndPoint(aPoint
);
1420 rTarget
.setControlPointA(aPoint
);
1421 rTarget
.setControlPointB(aPoint
);
1425 B2DPolygon
const & B2DPolygon::getDefaultAdaptiveSubdivision() const
1427 return mpPolygon
->getDefaultAdaptiveSubdivision(*this);
1430 B2DRange
const & B2DPolygon::getB2DRange() const
1432 return mpPolygon
->getB2DRange(*this);
1435 void B2DPolygon::append(const B2DPolygon
& rPoly
, sal_uInt32 nIndex
, sal_uInt32 nCount
)
1441 nCount
= rPoly
.count();
1444 if(nIndex
== 0 && nCount
== rPoly
.count())
1446 mpPolygon
->insert(mpPolygon
->count(), *rPoly
.mpPolygon
);
1450 OSL_ENSURE(nIndex
+ nCount
<= rPoly
.mpPolygon
->count(), "B2DPolygon Append outside range (!)");
1451 ImplB2DPolygon
aTempPoly(*rPoly
.mpPolygon
, nIndex
, nCount
);
1452 mpPolygon
->insert(mpPolygon
->count(), aTempPoly
);
1457 void B2DPolygon::remove(sal_uInt32 nIndex
, sal_uInt32 nCount
)
1459 OSL_ENSURE(nIndex
+ nCount
<= mpPolygon
->count(), "B2DPolygon Remove outside range (!)");
1463 mpPolygon
->remove(nIndex
, nCount
);
1467 void B2DPolygon::clear()
1469 *mpPolygon
= ImplB2DPolygon();
1472 bool B2DPolygon::isClosed() const
1474 return mpPolygon
->isClosed();
1477 void B2DPolygon::setClosed(bool bNew
)
1479 if(isClosed() != bNew
)
1481 mpPolygon
->setClosed(bNew
);
1485 void B2DPolygon::flip()
1493 bool B2DPolygon::hasDoublePoints() const
1495 return (mpPolygon
->count() > 1 && mpPolygon
->hasDoublePoints());
1498 void B2DPolygon::removeDoublePoints()
1500 if(hasDoublePoints())
1502 mpPolygon
->removeDoublePointsAtBeginEnd();
1503 mpPolygon
->removeDoublePointsWholeTrack();
1507 void B2DPolygon::transform(const B2DHomMatrix
& rMatrix
)
1509 if(mpPolygon
->count() && !rMatrix
.isIdentity())
1511 mpPolygon
->transform(rMatrix
);
1515 void B2DPolygon::addOrReplaceSystemDependentDataInternal(SystemDependentData_SharedPtr
& rData
) const
1517 // Need to get ImplB2DPolygon* from cow_wrapper *without*
1518 // calling make_unique() here - we do not want to
1519 // 'modify' the ImplB2DPolygon, but add buffered data that
1520 // is valid for all referencing instances
1521 const B2DPolygon
* pMe(this);
1522 const ImplB2DPolygon
* pMyImpl(pMe
->mpPolygon
.get());
1524 const_cast<ImplB2DPolygon
*>(pMyImpl
)->addOrReplaceSystemDependentData(rData
);
1527 SystemDependentData_SharedPtr
B2DPolygon::getSystemDependantDataInternal(size_t hash_code
) const
1529 return mpPolygon
->getSystemDependentData(hash_code
);
1532 } // end of namespace basegfx
1534 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */