diff options
Diffstat (limited to 'basegfx/source/polygon')
-rw-r--r-- | basegfx/source/polygon/b2dlinegeometry.cxx | 9 | ||||
-rw-r--r-- | basegfx/source/polygon/b2dpolygon.cxx | 50 | ||||
-rw-r--r-- | basegfx/source/polygon/b2dpolygonclipper.cxx | 7 | ||||
-rw-r--r-- | basegfx/source/polygon/b2dpolygoncutandtouch.cxx | 46 | ||||
-rw-r--r-- | basegfx/source/polygon/b2dpolygontools.cxx | 324 | ||||
-rw-r--r-- | basegfx/source/polygon/b2dsvgpolypolygon.cxx | 6 | ||||
-rw-r--r-- | basegfx/source/polygon/b3dpolygontools.cxx | 167 |
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; } } |