summaryrefslogtreecommitdiff
path: root/basegfx/source/polygon/b2dpolygontools.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'basegfx/source/polygon/b2dpolygontools.cxx')
-rw-r--r--basegfx/source/polygon/b2dpolygontools.cxx311
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);
}