Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / basegfx / source / polygon / b2dpolygon.cxx
bloba24cab41edcb40e18c73a557cd76bd87b82acbd4
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 //////////////////////////////////////////////////////////////////////////////
34 struct CoordinateData2D : public basegfx::B2DPoint
36 public:
37 CoordinateData2D() {}
39 explicit CoordinateData2D(const basegfx::B2DPoint& rData)
40 : B2DPoint(rData)
43 CoordinateData2D& operator=(const basegfx::B2DPoint& rData)
45 B2DPoint::operator=(rData);
46 return *this;
49 void transform(const basegfx::B2DHomMatrix& rMatrix)
51 *this *= rMatrix;
55 //////////////////////////////////////////////////////////////////////////////
57 class CoordinateDataArray2D
59 typedef ::std::vector< CoordinateData2D > CoordinateData2DVector;
61 CoordinateData2DVector maVector;
63 public:
64 explicit CoordinateDataArray2D(sal_uInt32 nCount)
65 : maVector(nCount)
69 explicit CoordinateDataArray2D(const CoordinateDataArray2D& rOriginal)
70 : maVector(rOriginal.maVector)
74 CoordinateDataArray2D(const CoordinateDataArray2D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
75 : maVector(rOriginal.maVector.begin() + nIndex, rOriginal.maVector.begin() + (nIndex + nCount))
79 sal_uInt32 count() const
81 return maVector.size();
84 bool operator==(const CoordinateDataArray2D& rCandidate) const
86 return (maVector == rCandidate.maVector);
89 const basegfx::B2DPoint& getCoordinate(sal_uInt32 nIndex) const
91 return maVector[nIndex];
94 void setCoordinate(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue)
96 maVector[nIndex] = rValue;
99 void reserve(sal_uInt32 nCount)
101 maVector.reserve(nCount);
104 void append(const CoordinateData2D& rValue)
106 maVector.push_back(rValue);
109 void insert(sal_uInt32 nIndex, const CoordinateData2D& rValue, sal_uInt32 nCount)
111 if(nCount)
113 // add nCount copies of rValue
114 CoordinateData2DVector::iterator aIndex(maVector.begin());
115 aIndex += nIndex;
116 maVector.insert(aIndex, nCount, rValue);
120 void insert(sal_uInt32 nIndex, const CoordinateDataArray2D& rSource)
122 const sal_uInt32 nCount(rSource.maVector.size());
124 if(nCount)
126 // insert data
127 CoordinateData2DVector::iterator aIndex(maVector.begin());
128 aIndex += nIndex;
129 CoordinateData2DVector::const_iterator aStart(rSource.maVector.begin());
130 CoordinateData2DVector::const_iterator aEnd(rSource.maVector.end());
131 maVector.insert(aIndex, aStart, aEnd);
135 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
137 if(nCount)
139 // remove point data
140 CoordinateData2DVector::iterator aStart(maVector.begin());
141 aStart += nIndex;
142 const CoordinateData2DVector::iterator aEnd(aStart + nCount);
143 maVector.erase(aStart, aEnd);
147 void flip(bool bIsClosed)
149 if(maVector.size() > 1)
151 // to keep the same point at index 0, just flip all points except the
152 // first one when closed
153 const sal_uInt32 nHalfSize(bIsClosed ? (maVector.size() - 1) >> 1 : maVector.size() >> 1);
154 CoordinateData2DVector::iterator aStart(bIsClosed ? maVector.begin() + 1 : maVector.begin());
155 CoordinateData2DVector::iterator aEnd(maVector.end() - 1);
157 for(sal_uInt32 a(0); a < nHalfSize; a++)
159 ::std::swap(*aStart, *aEnd);
160 ++aStart;
161 --aEnd;
166 void removeDoublePointsAtBeginEnd()
168 // remove from end as long as there are at least two points
169 // and begin/end are equal
170 while((maVector.size() > 1) && (maVector[0] == maVector[maVector.size() - 1]))
172 maVector.pop_back();
176 void removeDoublePointsWholeTrack()
178 sal_uInt32 nIndex(0);
180 // test as long as there are at least two points and as long as the index
181 // is smaller or equal second last point
182 while((maVector.size() > 1) && (nIndex <= maVector.size() - 2))
184 if(maVector[nIndex] == maVector[nIndex + 1])
186 // if next is same as index, delete next
187 maVector.erase(maVector.begin() + (nIndex + 1));
189 else
191 // if different, step forward
192 nIndex++;
197 void transform(const basegfx::B2DHomMatrix& rMatrix)
199 CoordinateData2DVector::iterator aStart(maVector.begin());
200 CoordinateData2DVector::iterator aEnd(maVector.end());
202 for(; aStart != aEnd; ++aStart)
204 aStart->transform(rMatrix);
208 const basegfx::B2DPoint* begin() const
210 if(maVector.empty())
211 return 0;
212 else
213 return &maVector.front();
216 const basegfx::B2DPoint* end() const
218 if(maVector.empty())
219 return 0;
220 else
221 return (&maVector.back())+1;
224 basegfx::B2DPoint* begin()
226 if(maVector.empty())
227 return 0;
228 else
229 return &maVector.front();
232 basegfx::B2DPoint* end()
234 if(maVector.empty())
235 return 0;
236 else
237 return (&maVector.back())+1;
241 //////////////////////////////////////////////////////////////////////////////
243 class ControlVectorPair2D
245 basegfx::B2DVector maPrevVector;
246 basegfx::B2DVector maNextVector;
248 public:
249 explicit ControlVectorPair2D() {}
251 const basegfx::B2DVector& getPrevVector() const
253 return maPrevVector;
256 void setPrevVector(const basegfx::B2DVector& rValue)
258 if(rValue != maPrevVector)
259 maPrevVector = rValue;
262 const basegfx::B2DVector& getNextVector() const
264 return maNextVector;
267 void setNextVector(const basegfx::B2DVector& rValue)
269 if(rValue != maNextVector)
270 maNextVector = rValue;
273 bool operator==(const ControlVectorPair2D& rData) const
275 return (maPrevVector == rData.getPrevVector() && maNextVector == rData.getNextVector());
278 void flip()
280 ::std::swap(maPrevVector, maNextVector);
284 //////////////////////////////////////////////////////////////////////////////
286 class ControlVectorArray2D
288 typedef ::std::vector< ControlVectorPair2D > ControlVectorPair2DVector;
290 ControlVectorPair2DVector maVector;
291 sal_uInt32 mnUsedVectors;
293 public:
294 explicit ControlVectorArray2D(sal_uInt32 nCount)
295 : maVector(nCount),
296 mnUsedVectors(0)
299 ControlVectorArray2D(const ControlVectorArray2D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
300 : maVector(),
301 mnUsedVectors(0)
303 ControlVectorPair2DVector::const_iterator aStart(rOriginal.maVector.begin());
304 aStart += nIndex;
305 ControlVectorPair2DVector::const_iterator aEnd(aStart);
306 aEnd += nCount;
307 maVector.reserve(nCount);
309 for(; aStart != aEnd; ++aStart)
311 if(!aStart->getPrevVector().equalZero())
312 mnUsedVectors++;
314 if(!aStart->getNextVector().equalZero())
315 mnUsedVectors++;
317 maVector.push_back(*aStart);
321 sal_uInt32 count() const
323 return maVector.size();
326 bool operator==(const ControlVectorArray2D& rCandidate) const
328 return (maVector == rCandidate.maVector);
331 bool isUsed() const
333 return (0 != mnUsedVectors);
336 const basegfx::B2DVector& getPrevVector(sal_uInt32 nIndex) const
338 return maVector[nIndex].getPrevVector();
341 void setPrevVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
343 bool bWasUsed(mnUsedVectors && !maVector[nIndex].getPrevVector().equalZero());
344 bool bIsUsed(!rValue.equalZero());
346 if(bWasUsed)
348 if(bIsUsed)
350 maVector[nIndex].setPrevVector(rValue);
352 else
354 maVector[nIndex].setPrevVector(basegfx::B2DVector::getEmptyVector());
355 mnUsedVectors--;
358 else
360 if(bIsUsed)
362 maVector[nIndex].setPrevVector(rValue);
363 mnUsedVectors++;
368 const basegfx::B2DVector& getNextVector(sal_uInt32 nIndex) const
370 return maVector[nIndex].getNextVector();
373 void setNextVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
375 bool bWasUsed(mnUsedVectors && !maVector[nIndex].getNextVector().equalZero());
376 bool bIsUsed(!rValue.equalZero());
378 if(bWasUsed)
380 if(bIsUsed)
382 maVector[nIndex].setNextVector(rValue);
384 else
386 maVector[nIndex].setNextVector(basegfx::B2DVector::getEmptyVector());
387 mnUsedVectors--;
390 else
392 if(bIsUsed)
394 maVector[nIndex].setNextVector(rValue);
395 mnUsedVectors++;
400 void append(const ControlVectorPair2D& rValue)
402 maVector.push_back(rValue);
404 if(!rValue.getPrevVector().equalZero())
405 mnUsedVectors += 1;
407 if(!rValue.getNextVector().equalZero())
408 mnUsedVectors += 1;
411 void insert(sal_uInt32 nIndex, const ControlVectorPair2D& rValue, sal_uInt32 nCount)
413 if(nCount)
415 // add nCount copies of rValue
416 ControlVectorPair2DVector::iterator aIndex(maVector.begin());
417 aIndex += nIndex;
418 maVector.insert(aIndex, nCount, rValue);
420 if(!rValue.getPrevVector().equalZero())
421 mnUsedVectors += nCount;
423 if(!rValue.getNextVector().equalZero())
424 mnUsedVectors += nCount;
428 void insert(sal_uInt32 nIndex, const ControlVectorArray2D& rSource)
430 const sal_uInt32 nCount(rSource.maVector.size());
432 if(nCount)
434 // insert data
435 ControlVectorPair2DVector::iterator aIndex(maVector.begin());
436 aIndex += nIndex;
437 ControlVectorPair2DVector::const_iterator aStart(rSource.maVector.begin());
438 ControlVectorPair2DVector::const_iterator aEnd(rSource.maVector.end());
439 maVector.insert(aIndex, aStart, aEnd);
441 for(; aStart != aEnd; ++aStart)
443 if(!aStart->getPrevVector().equalZero())
444 mnUsedVectors++;
446 if(!aStart->getNextVector().equalZero())
447 mnUsedVectors++;
452 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
454 if(nCount)
456 const ControlVectorPair2DVector::iterator aDeleteStart(maVector.begin() + nIndex);
457 const ControlVectorPair2DVector::iterator aDeleteEnd(aDeleteStart + nCount);
458 ControlVectorPair2DVector::const_iterator aStart(aDeleteStart);
460 for(; mnUsedVectors && aStart != aDeleteEnd; ++aStart)
462 if(!aStart->getPrevVector().equalZero())
463 mnUsedVectors--;
465 if(mnUsedVectors && !aStart->getNextVector().equalZero())
466 mnUsedVectors--;
469 // remove point data
470 maVector.erase(aDeleteStart, aDeleteEnd);
474 void flip(bool bIsClosed)
476 if(maVector.size() > 1)
478 // to keep the same point at index 0, just flip all points except the
479 // first one when closed
480 const sal_uInt32 nHalfSize(bIsClosed ? (maVector.size() - 1) >> 1 : maVector.size() >> 1);
481 ControlVectorPair2DVector::iterator aStart(bIsClosed ? maVector.begin() + 1 : maVector.begin());
482 ControlVectorPair2DVector::iterator aEnd(maVector.end() - 1);
484 for(sal_uInt32 a(0); a < nHalfSize; a++)
486 // swap Prev and Next
487 aStart->flip();
488 aEnd->flip();
490 // swap entries
491 ::std::swap(*aStart, *aEnd);
493 ++aStart;
494 --aEnd;
497 if(aStart == aEnd)
499 // swap Prev and Next at middle element (if exists)
500 aStart->flip();
503 if(bIsClosed)
505 // swap Prev and Next at start element
506 maVector.begin()->flip();
512 //////////////////////////////////////////////////////////////////////////////
514 class ImplBufferedData
516 private:
517 // Possibility to hold the last subdivision
518 boost::scoped_ptr< basegfx::B2DPolygon > mpDefaultSubdivision;
520 // Possibility to hold the last B2DRange calculation
521 boost::scoped_ptr< basegfx::B2DRange > mpB2DRange;
523 public:
524 ImplBufferedData()
525 : mpDefaultSubdivision(),
526 mpB2DRange()
529 const basegfx::B2DPolygon& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon& rSource) const
531 if(!mpDefaultSubdivision)
533 const_cast< ImplBufferedData* >(this)->mpDefaultSubdivision.reset(new basegfx::B2DPolygon(basegfx::tools::adaptiveSubdivideByCount(rSource, 9)));
536 return *mpDefaultSubdivision;
539 const basegfx::B2DRange& getB2DRange(const basegfx::B2DPolygon& rSource) const
541 if(!mpB2DRange)
543 basegfx::B2DRange aNewRange;
544 const sal_uInt32 nPointCount(rSource.count());
546 if(nPointCount)
548 for(sal_uInt32 a(0); a < nPointCount; a++)
550 aNewRange.expand(rSource.getB2DPoint(a));
553 if(rSource.areControlPointsUsed())
555 const sal_uInt32 nEdgeCount(rSource.isClosed() ? nPointCount : nPointCount - 1);
557 if(nEdgeCount)
559 basegfx::B2DCubicBezier aEdge;
560 aEdge.setStartPoint(rSource.getB2DPoint(0));
562 for(sal_uInt32 b(0); b < nEdgeCount; b++)
564 const sal_uInt32 nNextIndex((b + 1) % nPointCount);
565 aEdge.setControlPointA(rSource.getNextControlPoint(b));
566 aEdge.setControlPointB(rSource.getPrevControlPoint(nNextIndex));
567 aEdge.setEndPoint(rSource.getB2DPoint(nNextIndex));
569 if(aEdge.isBezier())
571 const basegfx::B2DRange aBezierRangeWithControlPoints(aEdge.getRange());
573 if(!aNewRange.isInside(aBezierRangeWithControlPoints))
575 // the range with control points of the current edge is not completely
576 // inside the current range without control points. Expand current range by
577 // subdividing the bezier segment.
578 // Ideal here is a subdivision at the extreme values, so use
579 // getAllExtremumPositions to get all extremas in one run
580 ::std::vector< double > aExtremas;
582 aExtremas.reserve(4);
583 aEdge.getAllExtremumPositions(aExtremas);
585 const sal_uInt32 nExtremaCount(aExtremas.size());
587 for(sal_uInt32 c(0); c < nExtremaCount; c++)
589 aNewRange.expand(aEdge.interpolatePoint(aExtremas[c]));
594 // prepare next edge
595 aEdge.setStartPoint(aEdge.getEndPoint());
601 const_cast< ImplBufferedData* >(this)->mpB2DRange.reset(new basegfx::B2DRange(aNewRange));
604 return *mpB2DRange;
608 //////////////////////////////////////////////////////////////////////////////
610 class ImplB2DPolygon
612 private:
613 // The point vector. This vector exists always and defines the
614 // count of members.
615 CoordinateDataArray2D maPoints;
617 // The control point vectors. This vectors are created on demand
618 // and may be zero.
619 boost::scoped_ptr< ControlVectorArray2D > mpControlVector;
621 // buffered data for e.g. default subdivision and range
622 boost::scoped_ptr< ImplBufferedData > mpBufferedData;
624 // flag which decides if this polygon is opened or closed
625 bool mbIsClosed;
627 public:
628 const basegfx::B2DPolygon& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon& rSource) const
630 if(!mpControlVector || !mpControlVector->isUsed())
632 return rSource;
635 if(!mpBufferedData)
637 const_cast< ImplB2DPolygon* >(this)->mpBufferedData.reset(new ImplBufferedData);
640 return mpBufferedData->getDefaultAdaptiveSubdivision(rSource);
643 const basegfx::B2DRange& getB2DRange(const basegfx::B2DPolygon& rSource) const
645 if(!mpBufferedData)
647 const_cast< ImplB2DPolygon* >(this)->mpBufferedData.reset(new ImplBufferedData);
650 return mpBufferedData->getB2DRange(rSource);
653 ImplB2DPolygon()
654 : maPoints(0),
655 mpControlVector(),
656 mpBufferedData(),
657 mbIsClosed(false)
660 ImplB2DPolygon(const ImplB2DPolygon& rToBeCopied)
661 : maPoints(rToBeCopied.maPoints),
662 mpControlVector(),
663 mpBufferedData(),
664 mbIsClosed(rToBeCopied.mbIsClosed)
666 // complete initialization using copy
667 if(rToBeCopied.mpControlVector && rToBeCopied.mpControlVector->isUsed())
669 mpControlVector.reset( new ControlVectorArray2D(*rToBeCopied.mpControlVector) );
673 ImplB2DPolygon(const ImplB2DPolygon& rToBeCopied, sal_uInt32 nIndex, sal_uInt32 nCount)
674 : maPoints(rToBeCopied.maPoints, nIndex, nCount),
675 mpControlVector(),
676 mpBufferedData(),
677 mbIsClosed(rToBeCopied.mbIsClosed)
679 // complete initialization using partly copy
680 if(rToBeCopied.mpControlVector && rToBeCopied.mpControlVector->isUsed())
682 mpControlVector.reset( new ControlVectorArray2D(*rToBeCopied.mpControlVector, nIndex, nCount) );
684 if(!mpControlVector->isUsed())
685 mpControlVector.reset();
689 ImplB2DPolygon& operator=( const ImplB2DPolygon& rToBeCopied )
691 maPoints = rToBeCopied.maPoints;
692 mpControlVector.reset();
693 mpBufferedData.reset();
694 mbIsClosed = rToBeCopied.mbIsClosed;
696 // complete initialization using copy
697 if(rToBeCopied.mpControlVector && rToBeCopied.mpControlVector->isUsed())
698 mpControlVector.reset( new ControlVectorArray2D(*rToBeCopied.mpControlVector) );
700 return *this;
703 sal_uInt32 count() const
705 return maPoints.count();
708 bool isClosed() const
710 return mbIsClosed;
713 void setClosed(bool bNew)
715 if(bNew != mbIsClosed)
717 mpBufferedData.reset();
718 mbIsClosed = bNew;
722 bool operator==(const ImplB2DPolygon& rCandidate) const
724 if(mbIsClosed == rCandidate.mbIsClosed)
726 if(maPoints == rCandidate.maPoints)
728 bool bControlVectorsAreEqual(true);
730 if(mpControlVector)
732 if(rCandidate.mpControlVector)
734 bControlVectorsAreEqual = ((*mpControlVector) == (*rCandidate.mpControlVector));
736 else
738 // candidate has no control vector, so it's assumed all unused.
739 bControlVectorsAreEqual = !mpControlVector->isUsed();
742 else
744 if(rCandidate.mpControlVector)
746 // we have no control vector, so it's assumed all unused.
747 bControlVectorsAreEqual = !rCandidate.mpControlVector->isUsed();
751 if(bControlVectorsAreEqual)
753 return true;
758 return false;
761 const basegfx::B2DPoint& getPoint(sal_uInt32 nIndex) const
763 return maPoints.getCoordinate(nIndex);
766 void setPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue)
768 mpBufferedData.reset();
769 maPoints.setCoordinate(nIndex, rValue);
772 void reserve(sal_uInt32 nCount)
774 maPoints.reserve(nCount);
777 void append(const basegfx::B2DPoint& rPoint)
779 mpBufferedData.reset(); // TODO: is this needed?
780 const CoordinateData2D aCoordinate(rPoint);
781 maPoints.append(aCoordinate);
783 if(mpControlVector)
785 const ControlVectorPair2D aVectorPair;
786 mpControlVector->append(aVectorPair);
790 void insert(sal_uInt32 nIndex, const basegfx::B2DPoint& rPoint, sal_uInt32 nCount)
792 if(nCount)
794 mpBufferedData.reset();
795 CoordinateData2D aCoordinate(rPoint);
796 maPoints.insert(nIndex, aCoordinate, nCount);
798 if(mpControlVector)
800 ControlVectorPair2D aVectorPair;
801 mpControlVector->insert(nIndex, aVectorPair, nCount);
806 const basegfx::B2DVector& getPrevControlVector(sal_uInt32 nIndex) const
808 if(mpControlVector)
810 return mpControlVector->getPrevVector(nIndex);
812 else
814 return basegfx::B2DVector::getEmptyVector();
818 void setPrevControlVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
820 if(!mpControlVector)
822 if(!rValue.equalZero())
824 mpBufferedData.reset();
825 mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
826 mpControlVector->setPrevVector(nIndex, rValue);
829 else
831 mpBufferedData.reset();
832 mpControlVector->setPrevVector(nIndex, rValue);
834 if(!mpControlVector->isUsed())
835 mpControlVector.reset();
839 const basegfx::B2DVector& getNextControlVector(sal_uInt32 nIndex) const
841 if(mpControlVector)
843 return mpControlVector->getNextVector(nIndex);
845 else
847 return basegfx::B2DVector::getEmptyVector();
851 void setNextControlVector(sal_uInt32 nIndex, const basegfx::B2DVector& rValue)
853 if(!mpControlVector)
855 if(!rValue.equalZero())
857 mpBufferedData.reset();
858 mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
859 mpControlVector->setNextVector(nIndex, rValue);
862 else
864 mpBufferedData.reset();
865 mpControlVector->setNextVector(nIndex, rValue);
867 if(!mpControlVector->isUsed())
868 mpControlVector.reset();
872 bool areControlPointsUsed() const
874 return (mpControlVector && mpControlVector->isUsed());
877 void resetControlVectors(sal_uInt32 nIndex)
879 setPrevControlVector(nIndex, basegfx::B2DVector::getEmptyVector());
880 setNextControlVector(nIndex, basegfx::B2DVector::getEmptyVector());
883 void resetControlVectors()
885 mpBufferedData.reset();
886 mpControlVector.reset();
889 void setControlVectors(sal_uInt32 nIndex, const basegfx::B2DVector& rPrev, const basegfx::B2DVector& rNext)
891 setPrevControlVector(nIndex, rPrev);
892 setNextControlVector(nIndex, rNext);
895 void appendBezierSegment(const basegfx::B2DVector& rNext, const basegfx::B2DVector& rPrev, const basegfx::B2DPoint& rPoint)
897 mpBufferedData.reset();
898 const sal_uInt32 nCount(maPoints.count());
900 if(nCount)
902 setNextControlVector(nCount - 1, rNext);
905 insert(nCount, rPoint, 1);
906 setPrevControlVector(nCount, rPrev);
909 void insert(sal_uInt32 nIndex, const ImplB2DPolygon& rSource)
911 const sal_uInt32 nCount(rSource.maPoints.count());
913 if(nCount)
915 mpBufferedData.reset();
917 if(rSource.mpControlVector && rSource.mpControlVector->isUsed() && !mpControlVector)
919 mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) );
922 maPoints.insert(nIndex, rSource.maPoints);
924 if(rSource.mpControlVector)
926 mpControlVector->insert(nIndex, *rSource.mpControlVector);
928 if(!mpControlVector->isUsed())
929 mpControlVector.reset();
931 else if(mpControlVector)
933 ControlVectorPair2D aVectorPair;
934 mpControlVector->insert(nIndex, aVectorPair, nCount);
939 void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
941 if(nCount)
943 mpBufferedData.reset();
944 maPoints.remove(nIndex, nCount);
946 if(mpControlVector)
948 mpControlVector->remove(nIndex, nCount);
950 if(!mpControlVector->isUsed())
951 mpControlVector.reset();
956 void flip()
958 if(maPoints.count() > 1)
960 mpBufferedData.reset();
962 // flip points
963 maPoints.flip(mbIsClosed);
965 if(mpControlVector)
967 // flip control vector
968 mpControlVector->flip(mbIsClosed);
973 bool hasDoublePoints() const
975 if(mbIsClosed)
977 // check for same start and end point
978 const sal_uInt32 nIndex(maPoints.count() - 1);
980 if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
982 if(mpControlVector)
984 if(mpControlVector->getNextVector(nIndex).equalZero() && mpControlVector->getPrevVector(0).equalZero())
986 return true;
989 else
991 return true;
996 // test for range
997 for(sal_uInt32 a(0); a < maPoints.count() - 1; a++)
999 if(maPoints.getCoordinate(a) == maPoints.getCoordinate(a + 1))
1001 if(mpControlVector)
1003 if(mpControlVector->getNextVector(a).equalZero() && mpControlVector->getPrevVector(a + 1).equalZero())
1005 return true;
1008 else
1010 return true;
1015 return false;
1018 void removeDoublePointsAtBeginEnd()
1020 // Only remove DoublePoints at Begin and End when poly is closed
1021 if(mbIsClosed)
1023 mpBufferedData.reset();
1025 if(mpControlVector)
1027 bool bRemove;
1031 bRemove = false;
1033 if(maPoints.count() > 1)
1035 const sal_uInt32 nIndex(maPoints.count() - 1);
1037 if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
1039 if(mpControlVector)
1041 if(mpControlVector->getNextVector(nIndex).equalZero() && mpControlVector->getPrevVector(0).equalZero())
1043 bRemove = true;
1046 else
1048 bRemove = true;
1053 if(bRemove)
1055 const sal_uInt32 nIndex(maPoints.count() - 1);
1057 if(mpControlVector && !mpControlVector->getPrevVector(nIndex).equalZero())
1059 mpControlVector->setPrevVector(0, mpControlVector->getPrevVector(nIndex));
1062 remove(nIndex, 1);
1065 while(bRemove);
1067 else
1069 maPoints.removeDoublePointsAtBeginEnd();
1074 void removeDoublePointsWholeTrack()
1076 mpBufferedData.reset();
1078 if(mpControlVector)
1080 sal_uInt32 nIndex(0);
1082 // test as long as there are at least two points and as long as the index
1083 // is smaller or equal second last point
1084 while((maPoints.count() > 1) && (nIndex <= maPoints.count() - 2))
1086 bool bRemove(maPoints.getCoordinate(nIndex) == maPoints.getCoordinate(nIndex + 1));
1088 if(bRemove)
1090 if(mpControlVector)
1092 if(!mpControlVector->getNextVector(nIndex).equalZero() || !mpControlVector->getPrevVector(nIndex + 1).equalZero())
1094 bRemove = false;
1099 if(bRemove)
1101 if(mpControlVector && !mpControlVector->getPrevVector(nIndex).equalZero())
1103 mpControlVector->setPrevVector(nIndex + 1, mpControlVector->getPrevVector(nIndex));
1106 // if next is same as index and the control vectors are unused, delete index
1107 remove(nIndex, 1);
1109 else
1111 // if different, step forward
1112 nIndex++;
1116 else
1118 maPoints.removeDoublePointsWholeTrack();
1122 void transform(const basegfx::B2DHomMatrix& rMatrix)
1124 mpBufferedData.reset();
1126 if(mpControlVector)
1128 for(sal_uInt32 a(0); a < maPoints.count(); a++)
1130 basegfx::B2DPoint aCandidate = maPoints.getCoordinate(a);
1132 if(mpControlVector->isUsed())
1134 const basegfx::B2DVector& rPrevVector(mpControlVector->getPrevVector(a));
1135 const basegfx::B2DVector& rNextVector(mpControlVector->getNextVector(a));
1137 if(!rPrevVector.equalZero())
1139 basegfx::B2DVector aPrevVector(rMatrix * rPrevVector);
1140 mpControlVector->setPrevVector(a, aPrevVector);
1143 if(!rNextVector.equalZero())
1145 basegfx::B2DVector aNextVector(rMatrix * rNextVector);
1146 mpControlVector->setNextVector(a, aNextVector);
1150 aCandidate *= rMatrix;
1151 maPoints.setCoordinate(a, aCandidate);
1154 if(!mpControlVector->isUsed())
1155 mpControlVector.reset();
1157 else
1159 maPoints.transform(rMatrix);
1163 const basegfx::B2DPoint* begin() const
1165 return maPoints.begin();
1168 const basegfx::B2DPoint* end() const
1170 return maPoints.end();
1173 basegfx::B2DPoint* begin()
1175 mpBufferedData.reset();
1176 return maPoints.begin();
1179 basegfx::B2DPoint* end()
1181 mpBufferedData.reset();
1182 return maPoints.end();
1186 //////////////////////////////////////////////////////////////////////////////
1188 namespace basegfx
1190 namespace
1192 struct DefaultPolygon: public rtl::Static<B2DPolygon::ImplType, DefaultPolygon> {};
1195 B2DPolygon::B2DPolygon()
1196 : mpPolygon(DefaultPolygon::get())
1199 B2DPolygon::B2DPolygon(const B2DPolygon& rPolygon)
1200 : mpPolygon(rPolygon.mpPolygon)
1203 B2DPolygon::B2DPolygon(const B2DPolygon& rPolygon, sal_uInt32 nIndex, sal_uInt32 nCount)
1204 : mpPolygon(ImplB2DPolygon(*rPolygon.mpPolygon, nIndex, nCount))
1206 // TODO(P2): one extra temporary here (cow_wrapper copies
1207 // given ImplB2DPolygon into its internal impl_t wrapper type)
1208 OSL_ENSURE(nIndex + nCount <= rPolygon.mpPolygon->count(), "B2DPolygon constructor outside range (!)");
1211 B2DPolygon::~B2DPolygon()
1215 B2DPolygon& B2DPolygon::operator=(const B2DPolygon& rPolygon)
1217 mpPolygon = rPolygon.mpPolygon;
1218 return *this;
1221 void B2DPolygon::makeUnique()
1223 mpPolygon.make_unique();
1226 bool B2DPolygon::operator==(const B2DPolygon& rPolygon) const
1228 if(mpPolygon.same_object(rPolygon.mpPolygon))
1229 return true;
1231 return ((*mpPolygon) == (*rPolygon.mpPolygon));
1234 bool B2DPolygon::operator!=(const B2DPolygon& rPolygon) const
1236 return !(*this == rPolygon);
1239 sal_uInt32 B2DPolygon::count() const
1241 return mpPolygon->count();
1244 B2DPoint B2DPolygon::getB2DPoint(sal_uInt32 nIndex) const
1246 OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1248 return mpPolygon->getPoint(nIndex);
1251 void B2DPolygon::setB2DPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1253 OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1255 if(mpPolygon->getPoint(nIndex) != rValue)
1257 mpPolygon->setPoint(nIndex, rValue);
1261 void B2DPolygon::reserve(sal_uInt32 nCount)
1263 mpPolygon->reserve(nCount);
1266 void B2DPolygon::insert(sal_uInt32 nIndex, const B2DPoint& rPoint, sal_uInt32 nCount)
1268 OSL_ENSURE(nIndex <= mpPolygon->count(), "B2DPolygon Insert outside range (!)");
1270 if(nCount)
1272 mpPolygon->insert(nIndex, rPoint, nCount);
1276 void B2DPolygon::append(const B2DPoint& rPoint, sal_uInt32 nCount)
1278 if(nCount)
1280 mpPolygon->insert(mpPolygon->count(), rPoint, nCount);
1284 void B2DPolygon::append(const B2DPoint& rPoint)
1286 mpPolygon->append(rPoint);
1289 B2DPoint B2DPolygon::getPrevControlPoint(sal_uInt32 nIndex) const
1291 OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1293 if(mpPolygon->areControlPointsUsed())
1295 return mpPolygon->getPoint(nIndex) + mpPolygon->getPrevControlVector(nIndex);
1297 else
1299 return mpPolygon->getPoint(nIndex);
1303 B2DPoint B2DPolygon::getNextControlPoint(sal_uInt32 nIndex) const
1305 OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1307 if(mpPolygon->areControlPointsUsed())
1309 return mpPolygon->getPoint(nIndex) + mpPolygon->getNextControlVector(nIndex);
1311 else
1313 return mpPolygon->getPoint(nIndex);
1317 void B2DPolygon::setPrevControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1319 OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1320 const basegfx::B2DVector aNewVector(rValue - mpPolygon->getPoint(nIndex));
1322 if(mpPolygon->getPrevControlVector(nIndex) != aNewVector)
1324 mpPolygon->setPrevControlVector(nIndex, aNewVector);
1328 void B2DPolygon::setNextControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue)
1330 OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1331 const basegfx::B2DVector aNewVector(rValue - mpPolygon->getPoint(nIndex));
1333 if(mpPolygon->getNextControlVector(nIndex) != aNewVector)
1335 mpPolygon->setNextControlVector(nIndex, aNewVector);
1339 void B2DPolygon::setControlPoints(sal_uInt32 nIndex, const basegfx::B2DPoint& rPrev, const basegfx::B2DPoint& rNext)
1341 OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1342 const B2DPoint aPoint(mpPolygon->getPoint(nIndex));
1343 const basegfx::B2DVector aNewPrev(rPrev - aPoint);
1344 const basegfx::B2DVector aNewNext(rNext - aPoint);
1346 if(mpPolygon->getPrevControlVector(nIndex) != aNewPrev || mpPolygon->getNextControlVector(nIndex) != aNewNext)
1348 mpPolygon->setControlVectors(nIndex, aNewPrev, aNewNext);
1352 void B2DPolygon::resetPrevControlPoint(sal_uInt32 nIndex)
1354 OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1356 if(mpPolygon->areControlPointsUsed() && !mpPolygon->getPrevControlVector(nIndex).equalZero())
1358 mpPolygon->setPrevControlVector(nIndex, B2DVector::getEmptyVector());
1362 void B2DPolygon::resetNextControlPoint(sal_uInt32 nIndex)
1364 OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1366 if(mpPolygon->areControlPointsUsed() && !mpPolygon->getNextControlVector(nIndex).equalZero())
1368 mpPolygon->setNextControlVector(nIndex, B2DVector::getEmptyVector());
1372 void B2DPolygon::resetControlPoints()
1374 if(mpPolygon->areControlPointsUsed())
1376 mpPolygon->resetControlVectors();
1380 void B2DPolygon::appendBezierSegment(
1381 const B2DPoint& rNextControlPoint,
1382 const B2DPoint& rPrevControlPoint,
1383 const B2DPoint& rPoint)
1385 const B2DVector aNewNextVector(mpPolygon->count() ? B2DVector(rNextControlPoint - mpPolygon->getPoint(mpPolygon->count() - 1)) : B2DVector::getEmptyVector());
1386 const B2DVector aNewPrevVector(rPrevControlPoint - rPoint);
1388 if(aNewNextVector.equalZero() && aNewPrevVector.equalZero())
1390 mpPolygon->insert(mpPolygon->count(), rPoint, 1);
1392 else
1394 mpPolygon->appendBezierSegment(aNewNextVector, aNewPrevVector, rPoint);
1398 bool B2DPolygon::areControlPointsUsed() const
1400 return mpPolygon->areControlPointsUsed();
1403 bool B2DPolygon::isPrevControlPointUsed(sal_uInt32 nIndex) const
1405 OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1407 return (mpPolygon->areControlPointsUsed() && !mpPolygon->getPrevControlVector(nIndex).equalZero());
1410 bool B2DPolygon::isNextControlPointUsed(sal_uInt32 nIndex) const
1412 OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1414 return (mpPolygon->areControlPointsUsed() && !mpPolygon->getNextControlVector(nIndex).equalZero());
1417 B2VectorContinuity B2DPolygon::getContinuityInPoint(sal_uInt32 nIndex) const
1419 OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1421 if(mpPolygon->areControlPointsUsed())
1423 const B2DVector& rPrev(mpPolygon->getPrevControlVector(nIndex));
1424 const B2DVector& rNext(mpPolygon->getNextControlVector(nIndex));
1426 return getContinuity(rPrev, rNext);
1428 else
1430 return CONTINUITY_NONE;
1434 void B2DPolygon::getBezierSegment(sal_uInt32 nIndex, B2DCubicBezier& rTarget) const
1436 OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
1437 const bool bNextIndexValidWithoutClose(nIndex + 1 < mpPolygon->count());
1439 if(bNextIndexValidWithoutClose || mpPolygon->isClosed())
1441 const sal_uInt32 nNextIndex(bNextIndexValidWithoutClose ? nIndex + 1 : 0);
1442 rTarget.setStartPoint(mpPolygon->getPoint(nIndex));
1443 rTarget.setEndPoint(mpPolygon->getPoint(nNextIndex));
1445 if(mpPolygon->areControlPointsUsed())
1447 rTarget.setControlPointA(rTarget.getStartPoint() + mpPolygon->getNextControlVector(nIndex));
1448 rTarget.setControlPointB(rTarget.getEndPoint() + mpPolygon->getPrevControlVector(nNextIndex));
1450 else
1452 // no bezier, reset control poins at rTarget
1453 rTarget.setControlPointA(rTarget.getStartPoint());
1454 rTarget.setControlPointB(rTarget.getEndPoint());
1457 else
1459 // no valid edge at all, reset rTarget to current point
1460 const B2DPoint aPoint(mpPolygon->getPoint(nIndex));
1461 rTarget.setStartPoint(aPoint);
1462 rTarget.setEndPoint(aPoint);
1463 rTarget.setControlPointA(aPoint);
1464 rTarget.setControlPointB(aPoint);
1468 B2DPolygon B2DPolygon::getDefaultAdaptiveSubdivision() const
1470 return mpPolygon->getDefaultAdaptiveSubdivision(*this);
1473 B2DRange B2DPolygon::getB2DRange() const
1475 return mpPolygon->getB2DRange(*this);
1478 void B2DPolygon::append(const B2DPolygon& rPoly, sal_uInt32 nIndex, sal_uInt32 nCount)
1480 if(rPoly.count())
1482 if(!nCount)
1484 nCount = rPoly.count();
1487 if(0 == nIndex && nCount == rPoly.count())
1489 mpPolygon->insert(mpPolygon->count(), *rPoly.mpPolygon);
1491 else
1493 OSL_ENSURE(nIndex + nCount <= rPoly.mpPolygon->count(), "B2DPolygon Append outside range (!)");
1494 ImplB2DPolygon aTempPoly(*rPoly.mpPolygon, nIndex, nCount);
1495 mpPolygon->insert(mpPolygon->count(), aTempPoly);
1500 void B2DPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
1502 OSL_ENSURE(nIndex + nCount <= mpPolygon->count(), "B2DPolygon Remove outside range (!)");
1504 if(nCount)
1506 mpPolygon->remove(nIndex, nCount);
1510 void B2DPolygon::clear()
1512 mpPolygon = DefaultPolygon::get();
1515 bool B2DPolygon::isClosed() const
1517 return mpPolygon->isClosed();
1520 void B2DPolygon::setClosed(bool bNew)
1522 if(isClosed() != bNew)
1524 mpPolygon->setClosed(bNew);
1528 void B2DPolygon::flip()
1530 if(count() > 1)
1532 mpPolygon->flip();
1536 bool B2DPolygon::hasDoublePoints() const
1538 return (mpPolygon->count() > 1 && mpPolygon->hasDoublePoints());
1541 void B2DPolygon::removeDoublePoints()
1543 if(hasDoublePoints())
1545 mpPolygon->removeDoublePointsAtBeginEnd();
1546 mpPolygon->removeDoublePointsWholeTrack();
1550 void B2DPolygon::transform(const B2DHomMatrix& rMatrix)
1552 if(mpPolygon->count() && !rMatrix.isIdentity())
1554 mpPolygon->transform(rMatrix);
1558 } // end of namespace basegfx
1560 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */