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