summaryrefslogtreecommitdiff
path: root/basegfx/source/polygon
diff options
context:
space:
mode:
Diffstat (limited to 'basegfx/source/polygon')
-rw-r--r--basegfx/source/polygon/b2dlinegeometry.cxx9
-rw-r--r--basegfx/source/polygon/b2dpolygon.cxx50
-rw-r--r--basegfx/source/polygon/b2dpolygonclipper.cxx7
-rw-r--r--basegfx/source/polygon/b2dpolygoncutandtouch.cxx46
-rw-r--r--basegfx/source/polygon/b2dpolygontools.cxx324
-rw-r--r--basegfx/source/polygon/b2dsvgpolypolygon.cxx6
-rw-r--r--basegfx/source/polygon/b3dpolygontools.cxx167
7 files changed, 381 insertions, 228 deletions
diff --git a/basegfx/source/polygon/b2dlinegeometry.cxx b/basegfx/source/polygon/b2dlinegeometry.cxx
index 1a9264ab769e..c22b5ea94011 100644
--- a/basegfx/source/polygon/b2dlinegeometry.cxx
+++ b/basegfx/source/polygon/b2dlinegeometry.cxx
@@ -40,6 +40,7 @@
#include <basegfx/range/b2drange.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/curve/b2dcubicbezier.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
//////////////////////////////////////////////////////////////////////////////
@@ -85,11 +86,9 @@ namespace basegfx
// get size of the arrow
const B2DRange aArrowSize(getRange(rArrow));
- // build ArrowTransform
- B2DHomMatrix aArrowTransform;
-
- // center in X, align with axis in Y
- aArrowTransform.translate(-aArrowSize.getCenter().getX(), -aArrowSize.getMinimum().getY());
+ // build ArrowTransform; center in X, align with axis in Y
+ B2DHomMatrix aArrowTransform(basegfx::tools::createTranslateB2DHomMatrix(
+ -aArrowSize.getCenter().getX(), -aArrowSize.getMinimum().getY()));
// scale to target size
const double fArrowScale(fWidth / (aArrowSize.getRange().getX()));
diff --git a/basegfx/source/polygon/b2dpolygon.cxx b/basegfx/source/polygon/b2dpolygon.cxx
index 467a4b90f516..48d00ddcec7d 100644
--- a/basegfx/source/polygon/b2dpolygon.cxx
+++ b/basegfx/source/polygon/b2dpolygon.cxx
@@ -7,7 +7,6 @@
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: b2dpolygon.cxx,v $
- * $Revision: 1.22 $
*
* This file is part of OpenOffice.org.
*
@@ -123,6 +122,16 @@ public:
maVector[nIndex].setCoordinate(rValue);
}
+ void reserve(sal_uInt32 nCount)
+ {
+ maVector.reserve(nCount);
+ }
+
+ void append(const CoordinateData2D& rValue)
+ {
+ maVector.push_back(rValue);
+ }
+
void insert(sal_uInt32 nIndex, const CoordinateData2D& rValue, sal_uInt32 nCount)
{
if(nCount)
@@ -380,6 +389,17 @@ public:
}
}
+ void append(const ControlVectorPair2D& rValue)
+ {
+ maVector.push_back(rValue);
+
+ if(!rValue.getPrevVector().equalZero())
+ mnUsedVectors += 1;
+
+ if(!rValue.getNextVector().equalZero())
+ mnUsedVectors += 1;
+ }
+
void insert(sal_uInt32 nIndex, const ControlVectorPair2D& rValue, sal_uInt32 nCount)
{
if(nCount)
@@ -741,6 +761,24 @@ public:
maPoints.setCoordinate(nIndex, rValue);
}
+ void reserve(sal_uInt32 nCount)
+ {
+ maPoints.reserve(nCount);
+ }
+
+ void append(const basegfx::B2DPoint& rPoint)
+ {
+ mpBufferedData.reset(); // TODO: is this needed?
+ const CoordinateData2D aCoordinate(rPoint);
+ maPoints.append(aCoordinate);
+
+ if(mpControlVector)
+ {
+ const ControlVectorPair2D aVectorPair;
+ mpControlVector->append(aVectorPair);
+ }
+ }
+
void insert(sal_uInt32 nIndex, const basegfx::B2DPoint& rPoint, sal_uInt32 nCount)
{
if(nCount)
@@ -1190,6 +1228,11 @@ namespace basegfx
}
}
+ void B2DPolygon::reserve(sal_uInt32 nCount)
+ {
+ mpPolygon->reserve(nCount);
+ }
+
void B2DPolygon::insert(sal_uInt32 nIndex, const B2DPoint& rPoint, sal_uInt32 nCount)
{
OSL_ENSURE(nIndex <= mpPolygon->count(), "B2DPolygon Insert outside range (!)");
@@ -1208,6 +1251,11 @@ namespace basegfx
}
}
+ void B2DPolygon::append(const B2DPoint& rPoint)
+ {
+ mpPolygon->append(rPoint);
+ }
+
B2DPoint B2DPolygon::getPrevControlPoint(sal_uInt32 nIndex) const
{
OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)");
diff --git a/basegfx/source/polygon/b2dpolygonclipper.cxx b/basegfx/source/polygon/b2dpolygonclipper.cxx
index f0d325942c07..87e44ed3d063 100644
--- a/basegfx/source/polygon/b2dpolygonclipper.cxx
+++ b/basegfx/source/polygon/b2dpolygonclipper.cxx
@@ -40,6 +40,7 @@
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/curve/b2dcubicbezier.hxx>
#include <basegfx/tools/rectcliptools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
//////////////////////////////////////////////////////////////////////////////
@@ -361,11 +362,10 @@ namespace basegfx
else if(rCandidate.count())
{
const B2DVector aEdge(rPointB - rPointA);
- B2DHomMatrix aMatrixTransform;
B2DPolygon aCandidate(rCandidate);
// translate and rotate polygon so that given edge is on x axis
- aMatrixTransform.translate(-rPointA.getX(), -rPointA.getY());
+ B2DHomMatrix aMatrixTransform(basegfx::tools::createTranslateB2DHomMatrix(-rPointA.getX(), -rPointA.getY()));
aMatrixTransform.rotate(-atan2(aEdge.getY(), aEdge.getX()));
aCandidate.transform(aMatrixTransform);
@@ -395,11 +395,10 @@ namespace basegfx
else if(rCandidate.count())
{
const B2DVector aEdge(rPointB - rPointA);
- B2DHomMatrix aMatrixTransform;
B2DPolyPolygon aCandidate(rCandidate);
// translate and rotate polygon so that given edge is on x axis
- aMatrixTransform.translate(-rPointA.getX(), -rPointA.getY());
+ B2DHomMatrix aMatrixTransform(basegfx::tools::createTranslateB2DHomMatrix(-rPointA.getX(), -rPointA.getY()));
aMatrixTransform.rotate(-atan2(aEdge.getY(), aEdge.getX()));
aCandidate.transform(aMatrixTransform);
diff --git a/basegfx/source/polygon/b2dpolygoncutandtouch.cxx b/basegfx/source/polygon/b2dpolygoncutandtouch.cxx
index 26016942717d..da6ff8904725 100644
--- a/basegfx/source/polygon/b2dpolygoncutandtouch.cxx
+++ b/basegfx/source/polygon/b2dpolygoncutandtouch.cxx
@@ -7,7 +7,6 @@
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: b2dpolygoncutandtouch.cxx,v $
- * $Revision: 1.8 $
*
* This file is part of OpenOffice.org.
*
@@ -430,6 +429,7 @@ namespace basegfx
// create subdivided polygons and find cuts between them
// Keep adaptiveSubdivideByCount due to needed quality
+ aTempPolygonA.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8);
aTempPolygonA.append(rCubicA.getStartPoint());
rCubicA.adaptiveSubdivideByCount(aTempPolygonA, SUBDIVIDE_FOR_CUT_TEST_COUNT);
aTempPolygonEdge.append(rCurrB);
@@ -470,8 +470,10 @@ namespace basegfx
// create subdivided polygons and find cuts between them
// Keep adaptiveSubdivideByCount due to needed quality
+ aTempPolygonA.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8);
aTempPolygonA.append(rCubicA.getStartPoint());
rCubicA.adaptiveSubdivideByCount(aTempPolygonA, SUBDIVIDE_FOR_CUT_TEST_COUNT);
+ aTempPolygonB.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8);
aTempPolygonB.append(rCubicB.getStartPoint());
rCubicB.adaptiveSubdivideByCount(aTempPolygonB, SUBDIVIDE_FOR_CUT_TEST_COUNT);
@@ -497,6 +499,13 @@ namespace basegfx
const B2DCubicBezier& rCubicA,
sal_uInt32 nInd, temporaryPointVector& rTempPoints)
{
+ // avoid expensive part of this method if possible
+ // TODO: use hasAnyExtremum() method instead when it becomes available
+ double fDummy;
+ const bool bHasAnyExtremum = rCubicA.getMinimumExtremumPosition( fDummy );
+ if( !bHasAnyExtremum )
+ return;
+
// find all self-intersections on the given bezier segment. Add an entry to the tempPoints
// for each self intersection point with the cut value describing the relative position on given
// bezier segment.
@@ -505,6 +514,7 @@ namespace basegfx
// create subdivided polygon and find cuts on it
// Keep adaptiveSubdivideByCount due to needed quality
+ aTempPolygon.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8);
aTempPolygon.append(rCubicA.getStartPoint());
rCubicA.adaptiveSubdivideByCount(aTempPolygon, SUBDIVIDE_FOR_CUT_TEST_COUNT);
findCuts(aTempPolygon, aTempPointVector);
@@ -557,7 +567,14 @@ namespace basegfx
const bool bEdgeBIsCurve(aCubicB.isBezier());
const B2DRange aRangeB(aCubicB.getRange());
- if(aRangeA.overlaps(aRangeB))
+ // only overlapping segments need to be tested
+ // consecutive segments touch of course
+ bool bOverlap = false;
+ if( b > a+1)
+ bOverlap = aRangeA.overlaps(aRangeB);
+ else
+ bOverlap = aRangeA.overlapsMore(aRangeB);
+ if( bOverlap)
{
if(bEdgeAIsCurve && bEdgeBIsCurve)
{
@@ -599,7 +616,13 @@ namespace basegfx
const B2DPoint aNextB(rCandidate.getB2DPoint(b + 1L == nPointCount ? 0L : b + 1L));
const B2DRange aRangeB(aCurrB, aNextB);
- if(aRangeA.overlaps(aRangeB))
+ // consecutive segments touch of course
+ bool bOverlap = false;
+ if( b > a+1)
+ bOverlap = aRangeA.overlaps(aRangeB);
+ else
+ bOverlap = aRangeA.overlapsMore(aRangeB);
+ if( bOverlap)
{
findEdgeCutsTwoEdges(aCurrA, aNextA, aCurrB, aNextB, a, b, rTempPoints, rTempPoints);
}
@@ -688,6 +711,7 @@ namespace basegfx
// create subdivided polygon and find cuts on it
// Keep adaptiveSubdivideByCount due to needed quality
+ aTempPolygon.reserve(SUBDIVIDE_FOR_CUT_TEST_COUNT + 8);
aTempPolygon.append(rCubicA.getStartPoint());
rCubicA.adaptiveSubdivideByCount(aTempPolygon, SUBDIVIDE_FOR_CUT_TEST_COUNT);
findTouches(aTempPolygon, rPointPolygon, aTempPointVector);
@@ -796,7 +820,13 @@ namespace basegfx
const bool bEdgeBIsCurve(aCubicB.isBezier());
const B2DRange aRangeB(aCubicB.getRange());
- if(aRangeA.overlaps(aRangeB))
+ // consecutive segments touch of course
+ bool bOverlap = false;
+ if( b > a+1)
+ bOverlap = aRangeA.overlaps(aRangeB);
+ else
+ bOverlap = aRangeA.overlapsMore(aRangeB);
+ if( bOverlap)
{
if(bEdgeAIsCurve && bEdgeBIsCurve)
{
@@ -838,7 +868,13 @@ namespace basegfx
const B2DPoint aNextB(rCandidateB.getB2DPoint(b + 1L == nPointCountB ? 0L : b + 1L));
const B2DRange aRangeB(aCurrB, aNextB);
- if(aRangeA.overlaps(aRangeB))
+ // consecutive segments touch of course
+ bool bOverlap = false;
+ if( b > a+1)
+ bOverlap = aRangeA.overlaps(aRangeB);
+ else
+ bOverlap = aRangeA.overlapsMore(aRangeB);
+ if( bOverlap)
{
// test for simple edge-edge cuts
findEdgeCutsTwoEdges(aCurrA, aNextA, aCurrB, aNextB, a, b, rTempPointsA, rTempPointsB);
diff --git a/basegfx/source/polygon/b2dpolygontools.cxx b/basegfx/source/polygon/b2dpolygontools.cxx
index c1e5dc80d8c4..d62462b8c097 100644
--- a/basegfx/source/polygon/b2dpolygontools.cxx
+++ b/basegfx/source/polygon/b2dpolygontools.cxx
@@ -7,7 +7,6 @@
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: b2dpolygontools.cxx,v $
- * $Revision: 1.29.4.1 $
*
* This file is part of OpenOffice.org.
*
@@ -34,7 +33,6 @@
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <osl/diagnose.h>
#include <rtl/math.hxx>
-
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <basegfx/range/b2drange.hxx>
@@ -44,6 +42,8 @@
#include <basegfx/matrix/b3dhommatrix.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/curve/b2dbeziertools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <osl/mutex.hxx>
#include <numeric>
#include <limits>
@@ -55,6 +55,7 @@
#ifdef DBG_UTIL
static double fAngleBoundStartValue = ANGLE_BOUND_START_VALUE;
#endif
+#define STEPSPERQUARTER (3)
//////////////////////////////////////////////////////////////////////////////
@@ -192,6 +193,9 @@ namespace basegfx
B2DCubicBezier aBezier;
aBezier.setStartPoint(rCandidate.getB2DPoint(0));
+ // perf: try to avoid too many realloctions by guessing the result's pointcount
+ aRetval.reserve(nPointCount*4);
+
// add start point (always)
aRetval.append(aBezier.getStartPoint());
@@ -272,6 +276,9 @@ namespace basegfx
B2DCubicBezier aBezier;
aBezier.setStartPoint(rCandidate.getB2DPoint(0));
+ // perf: try to avoid too many realloctions by guessing the result's pointcount
+ aRetval.reserve(nPointCount*4);
+
// add start point (always)
aRetval.append(aBezier.getStartPoint());
@@ -342,6 +349,9 @@ namespace basegfx
B2DCubicBezier aBezier;
aBezier.setStartPoint(rCandidate.getB2DPoint(0));
+ // perf: try to avoid too many realloctions by guessing the result's pointcount
+ aRetval.reserve(nPointCount*4);
+
// add start point (always)
aRetval.append(aBezier.getStartPoint());
@@ -1832,145 +1842,106 @@ namespace basegfx
return createPolygonFromEllipse( rCenter, fRadius, fRadius );
}
- void appendUnitCircleQuadrant(B2DPolygon& rPolygon, sal_uInt32 nQuadrant)
+ B2DPolygon impCreateUnitCircle(sal_uInt32 nStartQuadrant)
{
- const double fZero(0.0);
- const double fOne(1.0);
+ B2DPolygon aUnitCircle;
const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
+ const double fScaledKappa(fKappa * (1.0 / STEPSPERQUARTER));
+ const B2DHomMatrix aRotateMatrix(createRotateB2DHomMatrix(F_PI2 / STEPSPERQUARTER));
+
+ B2DPoint aPoint(1.0, 0.0);
+ B2DPoint aForward(1.0, fScaledKappa);
+ B2DPoint aBackward(1.0, -fScaledKappa);
- // create closed unit-circle with 4 segments
- switch(nQuadrant)
+ if(0 != nStartQuadrant)
{
- case 0 : // first quadrant
- {
- rPolygon.append(B2DPoint(fOne, fZero));
- rPolygon.appendBezierSegment(B2DPoint(fOne, fKappa), B2DPoint(fKappa, fOne), B2DPoint(fZero, fOne));
- break;
- }
- case 1 : // second quadrant
- {
- rPolygon.append(B2DPoint(fZero, fOne));
- rPolygon.appendBezierSegment(B2DPoint(-fKappa, fOne), B2DPoint(-fOne, fKappa), B2DPoint(-fOne, fZero));
- break;
- }
- case 2 : // third quadrant
- {
- rPolygon.append(B2DPoint(-fOne, fZero));
- rPolygon.appendBezierSegment(B2DPoint(-fOne, -fKappa), B2DPoint(-fKappa, -fOne), B2DPoint(fZero, -fOne));
- break;
- }
- default : // last quadrant
- {
- rPolygon.append(B2DPoint(fZero, -fOne));
- rPolygon.appendBezierSegment(B2DPoint(fKappa, -fOne), B2DPoint(fOne, -fKappa), B2DPoint(fOne, fZero));
- break;
- }
+ const B2DHomMatrix aQuadrantMatrix(createRotateB2DHomMatrix(F_PI2 * (nStartQuadrant % 4)));
+ aPoint *= aQuadrantMatrix;
+ aBackward *= aQuadrantMatrix;
+ aForward *= aQuadrantMatrix;
}
- }
- B2DPolygon createPolygonFromUnitCircle(sal_uInt32 nStartQuadrant)
- {
- B2DPolygon aRetval;
+ aUnitCircle.append(aPoint);
- // create unit-circle with all 4 segments, close it
- appendUnitCircleQuadrant(aRetval, nStartQuadrant % 4); nStartQuadrant++;
- appendUnitCircleQuadrant(aRetval, nStartQuadrant % 4); nStartQuadrant++;
- appendUnitCircleQuadrant(aRetval, nStartQuadrant % 4); nStartQuadrant++;
- appendUnitCircleQuadrant(aRetval, nStartQuadrant % 4); nStartQuadrant++;
- aRetval.setClosed(true);
+ for(sal_uInt32 a(0); a < STEPSPERQUARTER * 4; a++)
+ {
+ aPoint *= aRotateMatrix;
+ aBackward *= aRotateMatrix;
+ aUnitCircle.appendBezierSegment(aForward, aBackward, aPoint);
+ aForward *= aRotateMatrix;
+ }
- // remove double points between segments created by segmented creation
- aRetval.removeDoublePoints();
+ aUnitCircle.setClosed(true);
+ aUnitCircle.removeDoublePoints();
- return aRetval;
+ return aUnitCircle;
}
- B2DPolygon createPolygonFromEllipse( const B2DPoint& rCenter, double fRadiusX, double fRadiusY )
+ B2DPolygon createPolygonFromUnitCircle(sal_uInt32 nStartQuadrant)
{
- const double fOne(1.0);
- B2DPolygon aRetval(createPolygonFromUnitCircle());
-
- // transformation necessary?
- const sal_Bool bScale(!fTools::equal(fRadiusX, fOne) || !fTools::equal(fRadiusY, fOne));
- const sal_Bool bTranslate(!rCenter.equalZero());
-
- if(bScale || bTranslate)
+ switch(nStartQuadrant % 4)
{
- B2DHomMatrix aMatrix;
-
- if(bScale)
+ case 1 :
{
- aMatrix.scale(fRadiusX, fRadiusY);
- }
-
- if(bTranslate)
- {
- aMatrix.translate(rCenter.getX(), rCenter.getY());
- }
+ static B2DPolygon aUnitCircleStartQuadrantOne;
- aRetval.transform(aMatrix);
- }
-
- return aRetval;
- }
-
- void appendUnitCircleQuadrantSegment(B2DPolygon& rPolygon, sal_uInt32 nQuadrant, double fStart, double fEnd)
- {
- OSL_ENSURE(fStart >= 0.0 && fStart <= 1.0, "appendUnitCircleQuadrantSegment: Access out of range (!)");
- OSL_ENSURE(fEnd >= 0.0 && fEnd <= 1.0, "appendUnitCircleQuadrantSegment: Access out of range (!)");
- OSL_ENSURE(fEnd >= fStart, "appendUnitCircleQuadrantSegment: Access out of range (!)");
- const double fOne(1.0);
- const bool bStartIsZero(fTools::equalZero(fStart));
- const bool bEndIsOne(fTools::equal(fEnd, fOne));
-
- if(bStartIsZero && bEndIsOne)
- {
- // add completely
- appendUnitCircleQuadrant(rPolygon, nQuadrant);
- }
- else
- {
- // split and add
- B2DPolygon aQuadrant;
- appendUnitCircleQuadrant(aQuadrant, nQuadrant);
- const bool bStartEndEqual(fTools::equal(fStart, fEnd));
+ if(!aUnitCircleStartQuadrantOne.count())
+ {
+ ::osl::Mutex m_mutex;
+ aUnitCircleStartQuadrantOne = impCreateUnitCircle(1);
+ }
- if(bStartEndEqual)
+ return aUnitCircleStartQuadrantOne;
+ }
+ case 2 :
{
- if(bStartIsZero)
+ static B2DPolygon aUnitCircleStartQuadrantTwo;
+
+ if(!aUnitCircleStartQuadrantTwo.count())
{
- // both zero, add start point
- rPolygon.append(aQuadrant.getB2DPoint(0L));
+ ::osl::Mutex m_mutex;
+ aUnitCircleStartQuadrantTwo = impCreateUnitCircle(2);
}
- else if(bEndIsOne)
+
+ return aUnitCircleStartQuadrantTwo;
+ }
+ case 3 :
+ {
+ static B2DPolygon aUnitCircleStartQuadrantThree;
+
+ if(!aUnitCircleStartQuadrantThree.count())
{
- // both one, add end point
- rPolygon.append(aQuadrant.getB2DPoint(1L));
+ ::osl::Mutex m_mutex;
+ aUnitCircleStartQuadrantThree = impCreateUnitCircle(3);
}
- else
- {
- // both equal but not zero, add split point
- B2DCubicBezier aCubicBezier(
- aQuadrant.getB2DPoint(0L), aQuadrant.getNextControlPoint(0L),
- aQuadrant.getPrevControlPoint(1L), aQuadrant.getB2DPoint(1L));
- aCubicBezier.split(fStart, &aCubicBezier, 0);
- rPolygon.append(aCubicBezier.getEndPoint());
- }
+ return aUnitCircleStartQuadrantThree;
}
- else
+ default : // case 0 :
{
- B2DCubicBezier aCubicBezier(
- aQuadrant.getB2DPoint(0L), aQuadrant.getNextControlPoint(0L),
- aQuadrant.getPrevControlPoint(1L), aQuadrant.getB2DPoint(1L));
+ static B2DPolygon aUnitCircleStartQuadrantZero;
+
+ if(!aUnitCircleStartQuadrantZero.count())
+ {
+ ::osl::Mutex m_mutex;
+ aUnitCircleStartQuadrantZero = impCreateUnitCircle(0);
+ }
- aCubicBezier = aCubicBezier.snippet(fStart, fEnd);
- rPolygon.append(aCubicBezier.getStartPoint());
- rPolygon.appendBezierSegment(aCubicBezier.getControlPointA(), aCubicBezier.getControlPointB(), aCubicBezier.getEndPoint());
+ return aUnitCircleStartQuadrantZero;
}
}
}
+ B2DPolygon createPolygonFromEllipse( const B2DPoint& rCenter, double fRadiusX, double fRadiusY )
+ {
+ B2DPolygon aRetval(createPolygonFromUnitCircle());
+ const B2DHomMatrix aMatrix(createScaleTranslateB2DHomMatrix(fRadiusX, fRadiusY, rCenter.getX(), rCenter.getY()));
+
+ aRetval.transform(aMatrix);
+
+ return aRetval;
+ }
+
B2DPolygon createPolygonFromUnitEllipseSegment( double fStart, double fEnd )
{
B2DPolygon aRetval;
@@ -1997,49 +1968,74 @@ namespace basegfx
fEnd = 0.0;
}
- const sal_uInt32 nQuadrantStart(sal_uInt32(fStart / F_PI2) % 4L);
- const sal_uInt32 nQuadrantEnd(sal_uInt32(fEnd / F_PI2) % 4L);
- sal_uInt32 nCurrentQuadrant(nQuadrantStart);
- bool bStartDone(false);
- bool bEndDone(false);
-
- do
+ if(fTools::equal(fStart, fEnd))
{
- if(!bStartDone && nQuadrantStart == nCurrentQuadrant)
- {
- if(nQuadrantStart == nQuadrantEnd && fTools::moreOrEqual(fEnd, fStart))
- {
- // both in one quadrant and defining the complete segment, create start to end
- double fSplitOffsetStart((fStart - (nCurrentQuadrant * F_PI2)) / F_PI2);
- double fSplitOffsetEnd((fEnd - (nCurrentQuadrant * F_PI2)) / F_PI2);
- appendUnitCircleQuadrantSegment(aRetval, nCurrentQuadrant, fSplitOffsetStart, fSplitOffsetEnd);
- bStartDone = bEndDone = true;
- }
- else
- {
- // create start to quadrant end
- const double fSplitOffsetStart((fStart - (nCurrentQuadrant * F_PI2)) / F_PI2);
- appendUnitCircleQuadrantSegment(aRetval, nCurrentQuadrant, fSplitOffsetStart, 1.0);
- bStartDone = true;
- }
- }
- else if(!bEndDone && nQuadrantEnd == nCurrentQuadrant)
+ // same start and end angle, add single point
+ aRetval.append(B2DPoint(cos(fStart), sin(fStart)));
+ }
+ else
+ {
+ const sal_uInt32 nSegments(STEPSPERQUARTER * 4);
+ const double fAnglePerSegment(F_PI2 / STEPSPERQUARTER);
+ const sal_uInt32 nStartSegment(sal_uInt32(fStart / fAnglePerSegment) % nSegments);
+ const sal_uInt32 nEndSegment(sal_uInt32(fEnd / fAnglePerSegment) % nSegments);
+ const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
+ const double fScaledKappa(fKappa * (1.0 / STEPSPERQUARTER));
+
+ B2DPoint aSegStart(cos(fStart), sin(fStart));
+ aRetval.append(aSegStart);
+
+ if(nStartSegment == nEndSegment && fTools::more(fEnd, fStart))
{
- // create quadrant start to end
- const double fSplitOffsetEnd((fEnd - (nCurrentQuadrant * F_PI2)) / F_PI2);
- appendUnitCircleQuadrantSegment(aRetval, nCurrentQuadrant, 0.0, fSplitOffsetEnd);
- bEndDone = true;
+ // start and end in one sector and in the right order, create in one segment
+ const B2DPoint aSegEnd(cos(fEnd), sin(fEnd));
+ const double fFactor(fScaledKappa * ((fEnd - fStart) / fAnglePerSegment));
+
+ aRetval.appendBezierSegment(
+ aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fFactor),
+ aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fFactor),
+ aSegEnd);
}
else
{
- // add quadrant completely
- appendUnitCircleQuadrant(aRetval, nCurrentQuadrant);
- }
+ double fSegEndRad((nStartSegment + 1) * fAnglePerSegment);
+ double fFactor(fScaledKappa * ((fSegEndRad - fStart) / fAnglePerSegment));
+ B2DPoint aSegEnd(cos(fSegEndRad), sin(fSegEndRad));
+
+ aRetval.appendBezierSegment(
+ aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fFactor),
+ aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fFactor),
+ aSegEnd);
+
+ sal_uInt32 nSegment((nStartSegment + 1) % nSegments);
+ aSegStart = aSegEnd;
+
+ while(nSegment != nEndSegment)
+ {
+ // No end in this sector, add full sector.
+ fSegEndRad = (nSegment + 1) * fAnglePerSegment;
+ aSegEnd = B2DPoint(cos(fSegEndRad), sin(fSegEndRad));
+
+ aRetval.appendBezierSegment(
+ aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fScaledKappa),
+ aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fScaledKappa),
+ aSegEnd);
+
+ nSegment = (nSegment + 1) % nSegments;
+ aSegStart = aSegEnd;
+ }
- // next step
- nCurrentQuadrant = (nCurrentQuadrant + 1L) % 4L;
+ // End in this sector
+ const double fSegStartRad(nSegment * fAnglePerSegment);
+ fFactor = fScaledKappa * ((fEnd - fSegStartRad) / fAnglePerSegment);
+ aSegEnd = B2DPoint(cos(fEnd), sin(fEnd));
+
+ aRetval.appendBezierSegment(
+ aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fFactor),
+ aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fFactor),
+ aSegEnd);
+ }
}
- while(!(bStartDone && bEndDone));
// remove double points between segments created by segmented creation
aRetval.removeDoublePoints();
@@ -2050,28 +2046,9 @@ namespace basegfx
B2DPolygon createPolygonFromEllipseSegment( const B2DPoint& rCenter, double fRadiusX, double fRadiusY, double fStart, double fEnd )
{
B2DPolygon aRetval(createPolygonFromUnitEllipseSegment(fStart, fEnd));
+ const B2DHomMatrix aMatrix(createScaleTranslateB2DHomMatrix(fRadiusX, fRadiusY, rCenter.getX(), rCenter.getY()));
- // transformation necessary?
- const double fOne(1.0);
- const sal_Bool bScale(!fTools::equal(fRadiusX, fOne) || !fTools::equal(fRadiusY, fOne));
- const sal_Bool bTranslate(!rCenter.equalZero());
-
- if(bScale || bTranslate)
- {
- B2DHomMatrix aMatrix;
-
- if(bScale)
- {
- aMatrix.scale(fRadiusX, fRadiusY);
- }
-
- if(bTranslate)
- {
- aMatrix.translate(rCenter.getX(), rCenter.getY());
- }
-
- aRetval.transform(aMatrix);
- }
+ aRetval.transform(aMatrix);
return aRetval;
}
@@ -2701,11 +2678,7 @@ namespace basegfx
if(nPointCount)
{
- B2DHomMatrix aMatrix;
-
- aMatrix.translate(-rCenter.getX(), -rCenter.getY());
- aMatrix.rotate(fAngle);
- aMatrix.translate(rCenter.getX(), rCenter.getY());
+ const B2DHomMatrix aMatrix(basegfx::tools::createRotateAroundPoint(rCenter, fAngle));
aRetval.transform(aMatrix);
}
@@ -3269,6 +3242,9 @@ namespace basegfx
B2DCubicBezier aBezier;
aBezier.setStartPoint(rCandidate.getB2DPoint(0));
+ // try to avoid costly reallocations
+ aRetval.reserve( nEdgeCount+1);
+
// add start point
aRetval.append(aBezier.getStartPoint());
diff --git a/basegfx/source/polygon/b2dsvgpolypolygon.cxx b/basegfx/source/polygon/b2dsvgpolypolygon.cxx
index 2247c237d90f..e38ec3809fb1 100644
--- a/basegfx/source/polygon/b2dsvgpolypolygon.cxx
+++ b/basegfx/source/polygon/b2dsvgpolypolygon.cxx
@@ -36,6 +36,7 @@
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <rtl/ustring.hxx>
#include <rtl/math.hxx>
@@ -705,7 +706,7 @@ namespace basegfx
// |y1'| = |-sin phi cos phi| |(y1 - y2)/2|
const B2DPoint p1(nLastX, nLastY);
const B2DPoint p2(nX, nY);
- B2DHomMatrix aTransform; aTransform.rotate(-fPhi*M_PI/180);
+ B2DHomMatrix aTransform(basegfx::tools::createRotateB2DHomMatrix(-fPhi*M_PI/180));
const B2DPoint p1_prime( aTransform * B2DPoint(((p1-p2)/2.0)) );
@@ -797,8 +798,7 @@ namespace basegfx
fTheta1, fTheta2 ));
// transform ellipse by rotation & move to final center
- aTransform.identity();
- aTransform.scale(fRX,fRY);
+ aTransform = basegfx::tools::createScaleB2DHomMatrix(fRX, fRY);
aTransform.translate(aCenter_prime.getX(),
aCenter_prime.getY());
aTransform.rotate(fPhi*M_PI/180);
diff --git a/basegfx/source/polygon/b3dpolygontools.cxx b/basegfx/source/polygon/b3dpolygontools.cxx
index ea303886dd88..52e0f0fcc36f 100644
--- a/basegfx/source/polygon/b3dpolygontools.cxx
+++ b/basegfx/source/polygon/b3dpolygontools.cxx
@@ -875,52 +875,147 @@ namespace basegfx
}
else
{
+ bool bRetval(false);
const B3DVector aPlaneNormal(rCandidate.getNormal());
if(!aPlaneNormal.equalZero())
{
- const double fAbsX(fabs(aPlaneNormal.getX()));
- const double fAbsY(fabs(aPlaneNormal.getY()));
- const double fAbsZ(fabs(aPlaneNormal.getZ()));
+ const sal_uInt32 nPointCount(rCandidate.count());
- if(fAbsX > fAbsY && fAbsX > fAbsZ)
+ if(nPointCount)
{
- // normal points mostly in X-Direction, use YZ-Polygon projection for check
- B3DHomMatrix aTrans;
+ B3DPoint aCurrentPoint(rCandidate.getB3DPoint(nPointCount - 1));
+ const double fAbsX(fabs(aPlaneNormal.getX()));
+ const double fAbsY(fabs(aPlaneNormal.getY()));
+ const double fAbsZ(fabs(aPlaneNormal.getZ()));
- aTrans.set(0, 0, 0.0);
- aTrans.set(0, 1, 1.0);
- aTrans.set(1, 1, 0.0);
- aTrans.set(1, 2, 1.0);
-
- const B2DPolygon aYZ(createB2DPolygonFromB3DPolygon(rCandidate, aTrans));
-
- return isInside(aYZ, B2DPoint(rPoint.getY(), rPoint.getZ()), bWithBorder);
- }
- else if(fAbsY > fAbsX && fAbsY > fAbsZ)
- {
- // normal points mostly in Y-Direction, use XZ-Polygon projection for check
- B3DHomMatrix aTrans;
-
- aTrans.set(1, 1, 0.0);
- aTrans.set(1, 2, 1.0);
-
- const B2DPolygon aXZ(createB2DPolygonFromB3DPolygon(rCandidate, aTrans));
-
- return isInside(aXZ, B2DPoint(rPoint.getX(), rPoint.getZ()), bWithBorder);
- }
- else
- {
- // normal points mostly in Z-Direction, use XY-Polygon projection for check
- B3DHomMatrix aTrans;
-
- const B2DPolygon aXY(createB2DPolygonFromB3DPolygon(rCandidate, aTrans));
-
- return isInside(aXY, B2DPoint(rPoint.getX(), rPoint.getY()), bWithBorder);
+ if(fAbsX > fAbsY && fAbsX > fAbsZ)
+ {
+ // normal points mostly in X-Direction, use YZ-Polygon projection for check
+ // x -> y, y -> z
+ for(sal_uInt32 a(0); a < nPointCount; a++)
+ {
+ const B3DPoint aPreviousPoint(aCurrentPoint);
+ aCurrentPoint = rCandidate.getB3DPoint(a);
+
+ // cross-over in Z?
+ const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ()));
+ const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ()));
+
+ if(bCompZA != bCompZB)
+ {
+ // cross-over in Y?
+ const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY()));
+ const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY()));
+
+ if(bCompYA == bCompYB)
+ {
+ if(bCompYA)
+ {
+ bRetval = !bRetval;
+ }
+ }
+ else
+ {
+ const double fCompare(
+ aCurrentPoint.getY() - (aCurrentPoint.getZ() - rPoint.getZ()) *
+ (aPreviousPoint.getY() - aCurrentPoint.getY()) /
+ (aPreviousPoint.getZ() - aCurrentPoint.getZ()));
+
+ if(fTools::more(fCompare, rPoint.getY()))
+ {
+ bRetval = !bRetval;
+ }
+ }
+ }
+ }
+ }
+ else if(fAbsY > fAbsX && fAbsY > fAbsZ)
+ {
+ // normal points mostly in Y-Direction, use XZ-Polygon projection for check
+ // x -> x, y -> z
+ for(sal_uInt32 a(0); a < nPointCount; a++)
+ {
+ const B3DPoint aPreviousPoint(aCurrentPoint);
+ aCurrentPoint = rCandidate.getB3DPoint(a);
+
+ // cross-over in Z?
+ const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ()));
+ const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ()));
+
+ if(bCompZA != bCompZB)
+ {
+ // cross-over in X?
+ const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX()));
+ const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX()));
+
+ if(bCompXA == bCompXB)
+ {
+ if(bCompXA)
+ {
+ bRetval = !bRetval;
+ }
+ }
+ else
+ {
+ const double fCompare(
+ aCurrentPoint.getX() - (aCurrentPoint.getZ() - rPoint.getZ()) *
+ (aPreviousPoint.getX() - aCurrentPoint.getX()) /
+ (aPreviousPoint.getZ() - aCurrentPoint.getZ()));
+
+ if(fTools::more(fCompare, rPoint.getX()))
+ {
+ bRetval = !bRetval;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // normal points mostly in Z-Direction, use XY-Polygon projection for check
+ // x -> x, y -> y
+ for(sal_uInt32 a(0); a < nPointCount; a++)
+ {
+ const B3DPoint aPreviousPoint(aCurrentPoint);
+ aCurrentPoint = rCandidate.getB3DPoint(a);
+
+ // cross-over in Y?
+ const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY()));
+ const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY()));
+
+ if(bCompYA != bCompYB)
+ {
+ // cross-over in X?
+ const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX()));
+ const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX()));
+
+ if(bCompXA == bCompXB)
+ {
+ if(bCompXA)
+ {
+ bRetval = !bRetval;
+ }
+ }
+ else
+ {
+ const double fCompare(
+ aCurrentPoint.getX() - (aCurrentPoint.getY() - rPoint.getY()) *
+ (aPreviousPoint.getX() - aCurrentPoint.getX()) /
+ (aPreviousPoint.getY() - aCurrentPoint.getY()));
+
+ if(fTools::more(fCompare, rPoint.getX()))
+ {
+ bRetval = !bRetval;
+ }
+ }
+ }
+ }
+ }
}
}
- return false;
+ return bRetval;
}
}