bump product version to 5.0.4.1
[LibreOffice.git] / basegfx / source / polygon / b2dpolygon.cxx
blob096c4a01f44d12deed5e56d3bee956abcc0198ff
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
29 #include <vector>
30 #include <algorithm>
32 struct CoordinateData2D : public basegfx::B2DPoint
34 public:
35 CoordinateData2D() {}
37 explicit CoordinateData2D(const basegfx::B2DPoint& rData)
38 : B2DPoint(rData)
41 CoordinateData2D& operator=(const basegfx::B2DPoint& rData)
43 B2DPoint::operator=(rData);
44 return *this;
47 void transform(const basegfx::B2DHomMatrix& rMatrix)
49 *this *= rMatrix;
53 class CoordinateDataArray2D
55 typedef ::std::vector< CoordinateData2D > CoordinateData2DVector;
57 CoordinateData2DVector maVector;
59 public:
60 explicit CoordinateDataArray2D(sal_uInt32 nCount)
61 : maVector(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)
107 if(nCount)
109 // add nCount copies of rValue
110 CoordinateData2DVector::iterator aIndex(maVector.begin());
111 aIndex += nIndex;
112 maVector.insert(aIndex, nCount, rValue);
116 void insert(sal_uInt32 nIndex, const CoordinateDataArray2D& rSource)
118 const sal_uInt32 nCount(rSource.maVector.size());
120 if(nCount)
122 // insert data
123 CoordinateData2DVector::iterator aIndex(maVector.begin());
124 aIndex += nIndex;
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)
133 if(nCount)
135 // remove point data
136 CoordinateData2DVector::iterator aStart(maVector.begin());
137 aStart += nIndex;
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);
156 ++aStart;
157 --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]))
168 maVector.pop_back();
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));
185 else
187 // if different, step forward
188 nIndex++;
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;
210 public:
211 explicit ControlVectorPair2D() {}
213 const basegfx::B2DVector& getPrevVector() const
215 return maPrevVector;
218 void setPrevVector(const basegfx::B2DVector& rValue)
220 if(rValue != maPrevVector)
221 maPrevVector = rValue;
224 const basegfx::B2DVector& getNextVector() const
226 return maNextVector;
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());
240 void flip()
242 ::std::swap(maPrevVector, maNextVector);
246 class ControlVectorArray2D
248 typedef ::std::vector< ControlVectorPair2D > ControlVectorPair2DVector;
250 ControlVectorPair2DVector maVector;
251 sal_uInt32 mnUsedVectors;
253 public:
254 explicit ControlVectorArray2D(sal_uInt32 nCount)
255 : maVector(nCount),
256 mnUsedVectors(0)
259 ControlVectorArray2D(const ControlVectorArray2D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
260 : maVector(),
261 mnUsedVectors(0)
263 ControlVectorPair2DVector::const_iterator aStart(rOriginal.maVector.begin());
264 aStart += nIndex;
265 ControlVectorPair2DVector::const_iterator aEnd(aStart);
266 aEnd += nCount;
267 maVector.reserve(nCount);
269 for(; aStart != aEnd; ++aStart)
271 if(!aStart->getPrevVector().equalZero())
272 mnUsedVectors++;
274 if(!aStart->getNextVector().equalZero())
275 mnUsedVectors++;
277 maVector.push_back(*aStart);
281 bool operator==(const ControlVectorArray2D& rCandidate) const
283 return (maVector == rCandidate.maVector);
286 bool isUsed() const
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());
301 if(bWasUsed)
303 if(bIsUsed)
305 maVector[nIndex].setPrevVector(rValue);
307 else
309 maVector[nIndex].setPrevVector(basegfx::B2DVector::getEmptyVector());
310 mnUsedVectors--;
313 else
315 if(bIsUsed)
317 maVector[nIndex].setPrevVector(rValue);
318 mnUsedVectors++;
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());
333 if(bWasUsed)
335 if(bIsUsed)
337 maVector[nIndex].setNextVector(rValue);
339 else
341 maVector[nIndex].setNextVector(basegfx::B2DVector::getEmptyVector());
342 mnUsedVectors--;
345 else
347 if(bIsUsed)
349 maVector[nIndex].setNextVector(rValue);
350 mnUsedVectors++;
355 void append(const ControlVectorPair2D& rValue)
357 maVector.push_back(rValue);
359 if(!rValue.getPrevVector().equalZero())
360 mnUsedVectors += 1;
362 if(!rValue.getNextVector().equalZero())
363 mnUsedVectors += 1;
366 void insert(sal_uInt32 nIndex, const ControlVectorPair2D& rValue, sal_uInt32 nCount)
368 if(nCount)
370 // add nCount copies of rValue
371 ControlVectorPair2DVector::iterator aIndex(maVector.begin());
372 aIndex += nIndex;
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());
387 if(nCount)
389 // insert data
390 ControlVectorPair2DVector::iterator aIndex(maVector.begin());
391 aIndex += nIndex;
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())
399 mnUsedVectors++;
401 if(!aStart->getNextVector().equalZero())
402 mnUsedVectors++;
407 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
409 if(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())
418 mnUsedVectors--;
420 if(mnUsedVectors && !aStart->getNextVector().equalZero())
421 mnUsedVectors--;
424 // remove point data
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
442 aStart->flip();
443 aEnd->flip();
445 // swap entries
446 ::std::swap(*aStart, *aEnd);
448 ++aStart;
449 --aEnd;
452 if(aStart == aEnd)
454 // swap Prev and Next at middle element (if exists)
455 aStart->flip();
458 if(bIsClosed)
460 // swap Prev and Next at start element
461 maVector.begin()->flip();
467 class ImplBufferedData
469 private:
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;
476 public:
477 ImplBufferedData()
478 : mpDefaultSubdivision(),
479 mpB2DRange()
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
494 if(!mpB2DRange)
496 basegfx::B2DRange aNewRange;
497 const sal_uInt32 nPointCount(rSource.count());
499 if(nPointCount)
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);
510 if(nEdgeCount)
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));
522 if(aEdge.isBezier())
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]));
547 // prepare next edge
548 aEdge.setStartPoint(aEdge.getEndPoint());
554 const_cast< ImplBufferedData* >(this)->mpB2DRange.reset(new basegfx::B2DRange(aNewRange));
557 return *mpB2DRange;
561 class ImplB2DPolygon
563 private:
564 // The point vector. This vector exists always and defines the
565 // count of members.
566 CoordinateDataArray2D maPoints;
568 // The control point vectors. This vectors are created on demand
569 // and may be zero.
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
576 bool mbIsClosed;
578 public:
579 const basegfx::B2DPolygon& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon& rSource) const
581 if(!mpControlVector || !mpControlVector->isUsed())
583 return rSource;
586 if(!mpBufferedData)
588 const_cast< ImplB2DPolygon* >(this)->mpBufferedData.reset(new ImplBufferedData);
591 return mpBufferedData->getDefaultAdaptiveSubdivision(rSource);
594 const basegfx::B2DRange& getB2DRange(const basegfx::B2DPolygon& rSource) const
596 if(!mpBufferedData)
598 const_cast< ImplB2DPolygon* >(this)->mpBufferedData.reset(new ImplBufferedData);
601 return mpBufferedData->getB2DRange(rSource);
604 ImplB2DPolygon()
605 : maPoints(0),
606 mpControlVector(),
607 mpBufferedData(),
608 mbIsClosed(false)
611 ImplB2DPolygon(const ImplB2DPolygon& rToBeCopied)
612 : maPoints(rToBeCopied.maPoints),
613 mpControlVector(),
614 mpBufferedData(),
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),
626 mpControlVector(),
627 mpBufferedData(),
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
649 return mbIsClosed;
652 void setClosed(bool bNew)
654 if(bNew != mbIsClosed)
656 mpBufferedData.reset();
657 mbIsClosed = bNew;
661 bool operator==(const ImplB2DPolygon& rCandidate) const
663 if(mbIsClosed == rCandidate.mbIsClosed)
665 if(maPoints == rCandidate.maPoints)
667 bool bControlVectorsAreEqual(true);
669 if(mpControlVector)
671 if(rCandidate.mpControlVector)
673 bControlVectorsAreEqual = ((*mpControlVector) == (*rCandidate.mpControlVector));
675 else
677 // candidate has no control vector, so it's assumed all unused.
678 bControlVectorsAreEqual = !mpControlVector->isUsed();
681 else
683 if(rCandidate.mpControlVector)
685 // we have no control vector, so it's assumed all unused.
686 bControlVectorsAreEqual = !rCandidate.mpControlVector->isUsed();
690 if(bControlVectorsAreEqual)
692 return true;
697 return false;
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);
722 if(mpControlVector)
724 const ControlVectorPair2D aVectorPair;
725 mpControlVector->append(aVectorPair);
729 void insert(sal_uInt32 nIndex, const basegfx::B2DPoint& rPoint, sal_uInt32 nCount)
731 if(nCount)
733 mpBufferedData.reset();
734 CoordinateData2D aCoordinate(rPoint);
735 maPoints.insert(nIndex, aCoordinate, nCount);
737 if(mpControlVector)
739 ControlVectorPair2D aVectorPair;
740 mpControlVector->insert(nIndex, aVectorPair, nCount);
745 const basegfx::B2DVector& getPrevControlVector(sal_uInt32 nIndex) const
747 if(mpControlVector)
749 return mpControlVector->getPrevVector(nIndex);
751 else
753 return basegfx::B2DVector::getEmptyVector();
757 void setPrevControlVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
759 if(!mpControlVector)
761 if(!rValue.equalZero())
763 mpBufferedData.reset();
764 mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
765 mpControlVector->setPrevVector(nIndex, rValue);
768 else
770 mpBufferedData.reset();
771 mpControlVector->setPrevVector(nIndex, rValue);
773 if(!mpControlVector->isUsed())
774 mpControlVector.reset();
778 const basegfx::B2DVector& getNextControlVector(sal_uInt32 nIndex) const
780 if(mpControlVector)
782 return mpControlVector->getNextVector(nIndex);
784 else
786 return basegfx::B2DVector::getEmptyVector();
790 void setNextControlVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
792 if(!mpControlVector)
794 if(!rValue.equalZero())
796 mpBufferedData.reset();
797 mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
798 mpControlVector->setNextVector(nIndex, rValue);
801 else
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());
833 if(nCount)
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());
846 if(nCount)
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)
874 if(nCount)
876 mpBufferedData.reset();
877 maPoints.remove(nIndex, nCount);
879 if(mpControlVector)
881 mpControlVector->remove(nIndex, nCount);
883 if(!mpControlVector->isUsed())
884 mpControlVector.reset();
889 void flip()
891 if(maPoints.count() > 1)
893 mpBufferedData.reset();
895 // flip points
896 maPoints.flip(mbIsClosed);
898 if(mpControlVector)
900 // flip control vector
901 mpControlVector->flip(mbIsClosed);
906 bool hasDoublePoints() const
908 if(mbIsClosed)
910 // check for same start and end point
911 const sal_uInt32 nIndex(maPoints.count() - 1);
913 if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
915 if(mpControlVector)
917 if(mpControlVector->getNextVector(nIndex).equalZero() && mpControlVector->getPrevVector(0).equalZero())
919 return true;
922 else
924 return true;
929 // test for range
930 for(sal_uInt32 a(0); a < maPoints.count() - 1; a++)
932 if(maPoints.getCoordinate(a) == maPoints.getCoordinate(a + 1))
934 if(mpControlVector)
936 if(mpControlVector->getNextVector(a).equalZero() && mpControlVector->getPrevVector(a + 1).equalZero())
938 return true;
941 else
943 return true;
948 return false;
951 void removeDoublePointsAtBeginEnd()
953 // Only remove DoublePoints at Begin and End when poly is closed
954 if(mbIsClosed)
956 mpBufferedData.reset();
958 if(mpControlVector)
960 bool bRemove;
964 bRemove = false;
966 if(maPoints.count() > 1)
968 const sal_uInt32 nIndex(maPoints.count() - 1);
970 if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
972 if(mpControlVector)
974 if(mpControlVector->getNextVector(nIndex).equalZero() && mpControlVector->getPrevVector(0).equalZero())
976 bRemove = true;
979 else
981 bRemove = true;
986 if(bRemove)
988 const sal_uInt32 nIndex(maPoints.count() - 1);
990 if(mpControlVector && !mpControlVector->getPrevVector(nIndex).equalZero())
992 mpControlVector->setPrevVector(0, mpControlVector->getPrevVector(nIndex));
995 remove(nIndex, 1);
998 while(bRemove);
1000 else
1002 maPoints.removeDoublePointsAtBeginEnd();
1007 void removeDoublePointsWholeTrack()
1009 mpBufferedData.reset();
1011 if(mpControlVector)
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));
1021 if(bRemove)
1023 if(mpControlVector)
1025 if(!mpControlVector->getNextVector(nIndex).equalZero() || !mpControlVector->getPrevVector(nIndex + 1).equalZero())
1027 bRemove = false;
1032 if(bRemove)
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
1040 remove(nIndex, 1);
1042 else
1044 // if different, step forward
1045 nIndex++;
1049 else
1051 maPoints.removeDoublePointsWholeTrack();
1055 void transform(const basegfx::B2DHomMatrix& rMatrix)
1057 mpBufferedData.reset();
1059 if(mpControlVector)
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();
1090 else
1092 maPoints.transform(rMatrix);
1097 namespace basegfx
1099 namespace
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;
1127 return *this;
1130 void B2DPolygon::makeUnique()
1132 mpPolygon.make_unique();
1135 bool B2DPolygon::operator==(const B2DPolygon& rPolygon) const
1137 if(mpPolygon.same_object(rPolygon.mpPolygon))
1138 return true;
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 (!)");
1179 if(nCount)
1181 mpPolygon->insert(nIndex, rPoint, nCount);
1185 void B2DPolygon::append(const B2DPoint& rPoint, sal_uInt32 nCount)
1187 if(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);
1206 else
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);
1220 else
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);
1301 else
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);
1337 else
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));
1359 else
1361 // no bezier, reset control poins at rTarget
1362 rTarget.setControlPointA(rTarget.getStartPoint());
1363 rTarget.setControlPointB(rTarget.getEndPoint());
1366 else
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)
1389 if(rPoly.count())
1391 if(!nCount)
1393 nCount = rPoly.count();
1396 if(0 == nIndex && nCount == rPoly.count())
1398 mpPolygon->insert(mpPolygon->count(), *rPoly.mpPolygon);
1400 else
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 (!)");
1413 if(nCount)
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()
1439 if(count() > 1)
1441 mpPolygon->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: */