diff options
author | Vladimir Glazounov <vg@openoffice.org> | 2008-08-19 23:01:59 +0000 |
---|---|---|
committer | Vladimir Glazounov <vg@openoffice.org> | 2008-08-19 23:01:59 +0000 |
commit | b7b8e1b5405ff07b5d8e543b819dd7eeeb7d4eee (patch) | |
tree | a3da92fd79246818f7f26a0c7a11f037ca85e75c /basegfx | |
parent | ba2d94d15a8ade2408bcde1c0b20307cd2efde4b (diff) |
INTEGRATION: CWS aw033 (1.13.2); FILE MERGED
2008/05/14 14:40:37 aw 1.13.2.9: RESYNC: (1.19-1.21); FILE MERGED
2007/11/27 11:57:02 aw 1.13.2.8: #i39532# added GetRange() to B2DPolygon
2007/11/26 11:21:59 aw 1.13.2.7: #i39532# reworked B2DPolygon default decomposition
2007/11/23 09:43:05 aw 1.13.2.6: #i39532# warning corrections
2007/11/22 14:56:58 aw 1.13.2.5: #i39532# polygon bezier changes
2007/08/09 22:03:50 aw 1.13.2.4: RESYNC: (1.18-1.19); FILE MERGED
2006/09/26 14:49:33 aw 1.13.2.3: RESYNC: (1.14-1.17); FILE MERGED
2006/05/12 11:36:05 aw 1.13.2.2: code changes for primitive support
2005/10/28 11:24:14 aw 1.13.2.1: #i39532#
Diffstat (limited to 'basegfx')
-rw-r--r-- | basegfx/source/polygon/b2dpolygon.cxx | 259 |
1 files changed, 242 insertions, 17 deletions
diff --git a/basegfx/source/polygon/b2dpolygon.cxx b/basegfx/source/polygon/b2dpolygon.cxx index ac4dfddaede9..467a4b90f516 100644 --- a/basegfx/source/polygon/b2dpolygon.cxx +++ b/basegfx/source/polygon/b2dpolygon.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: b2dpolygon.cxx,v $ - * $Revision: 1.21 $ + * $Revision: 1.22 $ * * This file is part of OpenOffice.org. * @@ -35,8 +35,9 @@ #include <basegfx/point/b2dpoint.hxx> #include <basegfx/vector/b2dvector.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/curve/b2dcubicbezier.hxx> #include <rtl/instance.hxx> - +#include <basegfx/polygon/b2dpolygontools.hxx> #include <boost/scoped_ptr.hpp> #include <vector> #include <algorithm> @@ -482,39 +483,169 @@ public: ////////////////////////////////////////////////////////////////////////////// +class ImplBufferedData +{ +private: + // Possibility to hold the last subdivision + boost::scoped_ptr< basegfx::B2DPolygon > mpDefaultSubdivision; + + // Possibility to hold the last B2DRange calculation + boost::scoped_ptr< basegfx::B2DRange > mpB2DRange; + +public: + ImplBufferedData() + : mpDefaultSubdivision(), + mpB2DRange() + {} + + const basegfx::B2DPolygon& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon& rSource) const + { + if(!mpDefaultSubdivision) + { + const_cast< ImplBufferedData* >(this)->mpDefaultSubdivision.reset(new basegfx::B2DPolygon(basegfx::tools::adaptiveSubdivideByCount(rSource, 9))); + } + + return *mpDefaultSubdivision; + } + + const basegfx::B2DRange& getB2DRange(const basegfx::B2DPolygon& rSource) const + { + if(!mpB2DRange) + { + basegfx::B2DRange aNewRange; + const sal_uInt32 nPointCount(rSource.count()); + + if(nPointCount) + { + for(sal_uInt32 a(0); a < nPointCount; a++) + { + aNewRange.expand(rSource.getB2DPoint(a)); + } + + if(rSource.areControlPointsUsed()) + { + const sal_uInt32 nEdgeCount(rSource.isClosed() ? nPointCount : nPointCount - 1); + + if(nEdgeCount) + { + basegfx::B2DCubicBezier aEdge; + aEdge.setStartPoint(rSource.getB2DPoint(0)); + + for(sal_uInt32 b(0); b < nEdgeCount; b++) + { + const sal_uInt32 nNextIndex((b + 1) % nPointCount); + aEdge.setControlPointA(rSource.getNextControlPoint(b)); + aEdge.setControlPointB(rSource.getPrevControlPoint(nNextIndex)); + aEdge.setEndPoint(rSource.getB2DPoint(nNextIndex)); + + if(aEdge.isBezier()) + { + const basegfx::B2DRange aBezierRangeWithControlPoints(aEdge.getRange()); + + if(!aNewRange.isInside(aBezierRangeWithControlPoints)) + { + // the range with control points of the current edge is not completely + // inside the current range without control points. Expand current range by + // subdividing the bezier segment. + // Ideal here is a subdivision at the extreme values, so use + // getAllExtremumPositions to get all extremas in one run + ::std::vector< double > aExtremas; + + aExtremas.reserve(4); + aEdge.getAllExtremumPositions(aExtremas); + + const sal_uInt32 nExtremaCount(aExtremas.size()); + + for(sal_uInt32 c(0); c < nExtremaCount; c++) + { + aNewRange.expand(aEdge.interpolatePoint(aExtremas[c])); + } + } + } + + // prepare next edge + aEdge.setStartPoint(aEdge.getEndPoint()); + } + } + } + } + + const_cast< ImplBufferedData* >(this)->mpB2DRange.reset(new basegfx::B2DRange(aNewRange)); + } + + return *mpB2DRange; + } +}; + +////////////////////////////////////////////////////////////////////////////// + class ImplB2DPolygon { +private: // The point vector. This vector exists always and defines the // count of members. CoordinateDataArray2D maPoints; // The control point vectors. This vectors are created on demand // and may be zero. - boost::scoped_ptr<ControlVectorArray2D> mpControlVector; + boost::scoped_ptr< ControlVectorArray2D > mpControlVector; + + // buffered data for e.g. default subdivision and range + boost::scoped_ptr< ImplBufferedData > mpBufferedData; // flag which decides if this polygon is opened or closed bool mbIsClosed; public: + const basegfx::B2DPolygon& getDefaultAdaptiveSubdivision(const basegfx::B2DPolygon& rSource) const + { + if(!mpControlVector || !mpControlVector->isUsed()) + { + return rSource; + } + + if(!mpBufferedData) + { + const_cast< ImplB2DPolygon* >(this)->mpBufferedData.reset(new ImplBufferedData); + } + + return mpBufferedData->getDefaultAdaptiveSubdivision(rSource); + } + + const basegfx::B2DRange& getB2DRange(const basegfx::B2DPolygon& rSource) const + { + if(!mpBufferedData) + { + const_cast< ImplB2DPolygon* >(this)->mpBufferedData.reset(new ImplBufferedData); + } + + return mpBufferedData->getB2DRange(rSource); + } + ImplB2DPolygon() : maPoints(0), mpControlVector(), + mpBufferedData(), mbIsClosed(false) {} ImplB2DPolygon(const ImplB2DPolygon& rToBeCopied) : maPoints(rToBeCopied.maPoints), mpControlVector(), + mpBufferedData(), mbIsClosed(rToBeCopied.mbIsClosed) { // complete initialization using copy if(rToBeCopied.mpControlVector && rToBeCopied.mpControlVector->isUsed()) + { mpControlVector.reset( new ControlVectorArray2D(*rToBeCopied.mpControlVector) ); + } } ImplB2DPolygon(const ImplB2DPolygon& rToBeCopied, sal_uInt32 nIndex, sal_uInt32 nCount) : maPoints(rToBeCopied.maPoints, nIndex, nCount), mpControlVector(), + mpBufferedData(), mbIsClosed(rToBeCopied.mbIsClosed) { // complete initialization using partly copy @@ -531,6 +662,7 @@ public: { maPoints = rToBeCopied.maPoints; mpControlVector.reset(); + mpBufferedData.reset(); mbIsClosed = rToBeCopied.mbIsClosed; // complete initialization using copy @@ -554,6 +686,7 @@ public: { if(bNew != mbIsClosed) { + mpBufferedData.reset(); mbIsClosed = bNew; } } @@ -604,6 +737,7 @@ public: void setPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue) { + mpBufferedData.reset(); maPoints.setCoordinate(nIndex, rValue); } @@ -611,6 +745,7 @@ public: { if(nCount) { + mpBufferedData.reset(); CoordinateData2D aCoordinate(rPoint); maPoints.insert(nIndex, aCoordinate, nCount); @@ -640,12 +775,14 @@ public: { if(!rValue.equalZero()) { + mpBufferedData.reset(); mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) ); mpControlVector->setPrevVector(nIndex, rValue); } } else { + mpBufferedData.reset(); mpControlVector->setPrevVector(nIndex, rValue); if(!mpControlVector->isUsed()) @@ -671,12 +808,14 @@ public: { if(!rValue.equalZero()) { + mpBufferedData.reset(); mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) ); mpControlVector->setNextVector(nIndex, rValue); } } else { + mpBufferedData.reset(); mpControlVector->setNextVector(nIndex, rValue); if(!mpControlVector->isUsed()) @@ -697,6 +836,7 @@ public: void resetControlVectors() { + mpBufferedData.reset(); mpControlVector.reset(); } @@ -708,6 +848,7 @@ public: void appendBezierSegment(const basegfx::B2DVector& rNext, const basegfx::B2DVector& rPrev, const basegfx::B2DPoint& rPoint) { + mpBufferedData.reset(); const sal_uInt32 nCount(maPoints.count()); if(nCount) @@ -725,6 +866,8 @@ public: if(nCount) { + mpBufferedData.reset(); + if(rSource.mpControlVector && rSource.mpControlVector->isUsed() && !mpControlVector) { mpControlVector.reset( new ControlVectorArray2D(maPoints.count()) ); @@ -751,6 +894,7 @@ public: { if(nCount) { + mpBufferedData.reset(); maPoints.remove(nIndex, nCount); if(mpControlVector) @@ -767,6 +911,8 @@ public: { if(maPoints.count() > 1) { + mpBufferedData.reset(); + // flip points maPoints.flip(mbIsClosed); @@ -828,6 +974,8 @@ public: // Only remove DoublePoints at Begin and End when poly is closed if(mbIsClosed) { + mpBufferedData.reset(); + if(mpControlVector) { bool bRemove; @@ -879,6 +1027,8 @@ public: void removeDoublePointsWholeTrack() { + mpBufferedData.reset(); + if(mpControlVector) { sal_uInt32 nIndex(0); @@ -925,6 +1075,8 @@ public: void transform(const basegfx::B2DHomMatrix& rMatrix) { + mpBufferedData.reset(); + if(mpControlVector) { for(sal_uInt32 a(0); a < maPoints.count(); a++) @@ -1021,14 +1173,14 @@ namespace basegfx return mpPolygon->count(); } - basegfx::B2DPoint B2DPolygon::getB2DPoint(sal_uInt32 nIndex) const + B2DPoint B2DPolygon::getB2DPoint(sal_uInt32 nIndex) const { OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); return mpPolygon->getPoint(nIndex); } - void B2DPolygon::setB2DPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue) + void B2DPolygon::setB2DPoint(sal_uInt32 nIndex, const B2DPoint& rValue) { OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); @@ -1038,7 +1190,7 @@ namespace basegfx } } - void B2DPolygon::insert(sal_uInt32 nIndex, const basegfx::B2DPoint& rPoint, sal_uInt32 nCount) + void B2DPolygon::insert(sal_uInt32 nIndex, const B2DPoint& rPoint, sal_uInt32 nCount) { OSL_ENSURE(nIndex <= mpPolygon->count(), "B2DPolygon Insert outside range (!)"); @@ -1048,7 +1200,7 @@ namespace basegfx } } - void B2DPolygon::append(const basegfx::B2DPoint& rPoint, sal_uInt32 nCount) + void B2DPolygon::append(const B2DPoint& rPoint, sal_uInt32 nCount) { if(nCount) { @@ -1056,7 +1208,7 @@ namespace basegfx } } - basegfx::B2DPoint B2DPolygon::getPrevControlPoint(sal_uInt32 nIndex) const + B2DPoint B2DPolygon::getPrevControlPoint(sal_uInt32 nIndex) const { OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); @@ -1070,7 +1222,7 @@ namespace basegfx } } - basegfx::B2DPoint B2DPolygon::getNextControlPoint(sal_uInt32 nIndex) const + B2DPoint B2DPolygon::getNextControlPoint(sal_uInt32 nIndex) const { OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); @@ -1084,7 +1236,7 @@ namespace basegfx } } - void B2DPolygon::setPrevControlPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue) + void B2DPolygon::setPrevControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue) { OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); const basegfx::B2DVector aNewVector(rValue - mpPolygon->getPoint(nIndex)); @@ -1095,7 +1247,7 @@ namespace basegfx } } - void B2DPolygon::setNextControlPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue) + void B2DPolygon::setNextControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue) { OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); const basegfx::B2DVector aNewVector(rValue - mpPolygon->getPoint(nIndex)); @@ -1159,12 +1311,12 @@ namespace basegfx } void B2DPolygon::appendBezierSegment( - const basegfx::B2DPoint& rNextControlPoint, - const basegfx::B2DPoint& rPrevControlPoint, - const basegfx::B2DPoint& rPoint) + const B2DPoint& rNextControlPoint, + const B2DPoint& rPrevControlPoint, + const B2DPoint& rPoint) { - const basegfx::B2DVector aNewNextVector(mpPolygon->count() ? basegfx::B2DVector(rNextControlPoint - mpPolygon->getPoint(mpPolygon->count() - 1)) : B2DVector::getEmptyVector()); - const basegfx::B2DVector aNewPrevVector(rPrevControlPoint - rPoint); + const B2DVector aNewNextVector(mpPolygon->count() ? B2DVector(rNextControlPoint - mpPolygon->getPoint(mpPolygon->count() - 1)) : B2DVector::getEmptyVector()); + const B2DVector aNewPrevVector(rPrevControlPoint - rPoint); if(aNewNextVector.equalZero() && aNewPrevVector.equalZero()) { @@ -1212,6 +1364,79 @@ namespace basegfx } } + bool B2DPolygon::isBezierSegment(sal_uInt32 nIndex) const + { + OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); + + if(mpPolygon->areControlPointsUsed()) + { + // Check if the edge exists + const bool bNextIndexValidWithoutClose(nIndex + 1 < mpPolygon->count()); + + if(bNextIndexValidWithoutClose || mpPolygon->isClosed()) + { + const sal_uInt32 nNextIndex(bNextIndexValidWithoutClose ? nIndex + 1 : 0); + return (!mpPolygon->getPrevControlVector(nNextIndex).equalZero() + || !mpPolygon->getNextControlVector(nIndex).equalZero()); + } + else + { + // no valid edge -> no bezier segment, even when local next + // vector may be used + return false; + } + } + else + { + // no control points -> no bezier segment + return false; + } + } + + void B2DPolygon::getBezierSegment(sal_uInt32 nIndex, B2DCubicBezier& rTarget) const + { + OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); + const bool bNextIndexValidWithoutClose(nIndex + 1 < mpPolygon->count()); + + if(bNextIndexValidWithoutClose || mpPolygon->isClosed()) + { + const sal_uInt32 nNextIndex(bNextIndexValidWithoutClose ? nIndex + 1 : 0); + rTarget.setStartPoint(mpPolygon->getPoint(nIndex)); + rTarget.setEndPoint(mpPolygon->getPoint(nNextIndex)); + + if(mpPolygon->areControlPointsUsed()) + { + rTarget.setControlPointA(rTarget.getStartPoint() + mpPolygon->getNextControlVector(nIndex)); + rTarget.setControlPointB(rTarget.getEndPoint() + mpPolygon->getPrevControlVector(nNextIndex)); + } + else + { + // no bezier, reset control poins at rTarget + rTarget.setControlPointA(rTarget.getStartPoint()); + rTarget.setControlPointB(rTarget.getEndPoint()); + } + } + else + { + // no valid edge at all, reset rTarget to current point + const B2DPoint aPoint(mpPolygon->getPoint(nIndex)); + rTarget.setStartPoint(aPoint); + rTarget.setEndPoint(aPoint); + rTarget.setControlPointA(aPoint); + rTarget.setControlPointB(aPoint); + } + } + + B2DPolygon B2DPolygon::getDefaultAdaptiveSubdivision() const + { + return mpPolygon->getDefaultAdaptiveSubdivision(*this); + } + + B2DRange B2DPolygon::getB2DRange() const + { + return mpPolygon->getB2DRange(*this); + } + void B2DPolygon::insert(sal_uInt32 nIndex, const B2DPolygon& rPoly, sal_uInt32 nIndex2, sal_uInt32 nCount) { OSL_ENSURE(nIndex <= mpPolygon->count(), "B2DPolygon Insert outside range (!)"); @@ -1308,7 +1533,7 @@ namespace basegfx } } - void B2DPolygon::transform(const basegfx::B2DHomMatrix& rMatrix) + void B2DPolygon::transform(const B2DHomMatrix& rMatrix) { if(mpPolygon->count() && !rMatrix.isIdentity()) { |