diff options
Diffstat (limited to 'basegfx/source/polygon/b2dpolygontools.cxx')
-rw-r--r-- | basegfx/source/polygon/b2dpolygontools.cxx | 311 |
1 files changed, 138 insertions, 173 deletions
diff --git a/basegfx/source/polygon/b2dpolygontools.cxx b/basegfx/source/polygon/b2dpolygontools.cxx index 7485387c6cb9..d62462b8c097 100644 --- a/basegfx/source/polygon/b2dpolygontools.cxx +++ b/basegfx/source/polygon/b2dpolygontools.cxx @@ -33,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> @@ -43,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> @@ -54,6 +55,7 @@ #ifdef DBG_UTIL static double fAngleBoundStartValue = ANGLE_BOUND_START_VALUE; #endif +#define STEPSPERQUARTER (3) ////////////////////////////////////////////////////////////////////////////// @@ -1840,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) - { - aMatrix.scale(fRadiusX, fRadiusY); - } - - if(bTranslate) + case 1 : { - aMatrix.translate(rCenter.getX(), rCenter.getY()); - } - - 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)); + static B2DPolygon aUnitCircleStartQuadrantOne; - 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; @@ -2005,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)); - // next step - nCurrentQuadrant = (nCurrentQuadrant + 1L) % 4L; + 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; + } + + // 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(); @@ -2058,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; } @@ -2709,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); } |