summaryrefslogtreecommitdiff
path: root/basegfx
diff options
context:
space:
mode:
authorVladimir Glazounov <vg@openoffice.org>2008-08-19 23:01:59 +0000
committerVladimir Glazounov <vg@openoffice.org>2008-08-19 23:01:59 +0000
commitb7b8e1b5405ff07b5d8e543b819dd7eeeb7d4eee (patch)
treea3da92fd79246818f7f26a0c7a11f037ca85e75c /basegfx
parentba2d94d15a8ade2408bcde1c0b20307cd2efde4b (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.cxx259
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())
{