basegfx/source/polygon/b2dpolygontools.cxx |   44 ++++++++++++++++++-----------
 1 file changed, 28 insertions(+), 16 deletions(-)

New commits:
commit fbc95e77d28f8a5a8f6442a64e5e0e52e98612c2
Author:     Regina Henschel <rb.hensc...@t-online.de>
AuthorDate: Tue Nov 20 14:57:07 2018 +0100
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Thu Nov 22 18:55:33 2018 +0100

    tdf#121425 Use better Bezier curves to approximate circle arc
    
    The distance between curve point and control point was calculated
    as linear scaling with ratio of central angle of the arc to pi/2.
    The patch replaces this with the mathematical correct formula.
    
    Change-Id: I0195e40bb99cd4bbcce95f7ac896158b7e7e3d29
    Reviewed-on: https://gerrit.libreoffice.org/63659
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/basegfx/source/polygon/b2dpolygontools.cxx 
b/basegfx/source/polygon/b2dpolygontools.cxx
index e0cfcdba1933..f005f2519026 100644
--- a/basegfx/source/polygon/b2dpolygontools.cxx
+++ b/basegfx/source/polygon/b2dpolygontools.cxx
@@ -1490,6 +1490,21 @@ namespace basegfx
             return false;
         }
 
+        // Calculates distance of curve point to its control point for a 
Bézier curve, that
+        // approximates a unit circle arc. fAngle is the center angle of the 
circle arc. The
+        // constrain 0<=fAngle<=pi/2 must not be violated to give a useful 
accuracy. For details
+        // and alternatives read document "ApproxCircleInfo.odt", attachment 
of bug tdf#121425.
+        static double impDistanceBezierPointToControl(double fAngle)
+        {
+            SAL_WARN_IF(fAngle < 0 || fAngle > F_PI2,"basegfx","angle not 
suitable for approximate circle");
+            if (0 <= fAngle && fAngle <= F_PI2)
+            {
+                return 4.0/3.0 * ( tan(fAngle/4.0));
+            }
+            else
+                return 0;
+        }
+
         B2DPolygon createPolygonFromRect( const B2DRectangle& rRect, double 
fRadiusX, double fRadiusY )
         {
             const double fZero(0.0);
@@ -1549,7 +1564,7 @@ namespace basegfx
                 B2DPolygon aRetval;
                 const double fBowX((rRect.getWidth() / 2.0) * fRadiusX);
                 const double fBowY((rRect.getHeight() / 2.0) * fRadiusY);
-                const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
+                const double fKappa(impDistanceBezierPointToControl(F_PI2));
 
                 // create start point at bottom center
                 if(!rtl::math::approxEqual(fOne, fRadiusX))
@@ -1657,13 +1672,12 @@ namespace basegfx
         static B2DPolygon impCreateUnitCircle(sal_uInt32 nStartQuadrant)
         {
             B2DPolygon aUnitCircle;
-            const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
-            const double fScaledKappa(fKappa * (1.0 / STEPSPERQUARTER));
+            const double fSegmentKappa = impDistanceBezierPointToControl(F_PI2 
/ STEPSPERQUARTER);
             const B2DHomMatrix aRotateMatrix(createRotateB2DHomMatrix(F_PI2 / 
STEPSPERQUARTER));
 
             B2DPoint aPoint(1.0, 0.0);
-            B2DPoint aForward(1.0, fScaledKappa);
-            B2DPoint aBackward(1.0, -fScaledKappa);
+            B2DPoint aForward(1.0, fSegmentKappa);
+            B2DPoint aBackward(1.0, -fSegmentKappa);
 
             if(nStartQuadrant != 0)
             {
@@ -1697,12 +1711,11 @@ namespace basegfx
                 B2DPolygon operator()()
                 {
                     B2DPolygon aUnitHalfCircle;
-                    const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
-                    const double fScaledKappa(fKappa * (1.0 / 
STEPSPERQUARTER));
+                    const double 
fSegmentKappa(impDistanceBezierPointToControl(F_PI2 / STEPSPERQUARTER));
                     const B2DHomMatrix 
aRotateMatrix(createRotateB2DHomMatrix(F_PI2 / STEPSPERQUARTER));
                     B2DPoint aPoint(1.0, 0.0);
-                    B2DPoint aForward(1.0, fScaledKappa);
-                    B2DPoint aBackward(1.0, -fScaledKappa);
+                    B2DPoint aForward(1.0, fSegmentKappa);
+                    B2DPoint aBackward(1.0, -fSegmentKappa);
 
                     aUnitHalfCircle.append(aPoint);
 
@@ -1815,8 +1828,7 @@ namespace basegfx
                 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));
+                const double 
fSegmentKappa(impDistanceBezierPointToControl(fAnglePerSegment));
 
                 B2DPoint aSegStart(cos(fStart), sin(fStart));
                 aRetval.append(aSegStart);
@@ -1825,7 +1837,7 @@ namespace basegfx
                 {
                     // 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));
+                    const double fFactor(impDistanceBezierPointToControl(fEnd 
- fStart));
 
                     aRetval.appendBezierSegment(
                         aSegStart + (B2DPoint(-aSegStart.getY(), 
aSegStart.getX()) * fFactor),
@@ -1835,7 +1847,7 @@ namespace basegfx
                 else
                 {
                     double fSegEndRad((nStartSegment + 1) * fAnglePerSegment);
-                    double fFactor(fScaledKappa * ((fSegEndRad - fStart) / 
fAnglePerSegment));
+                    double fFactor(impDistanceBezierPointToControl(fSegEndRad 
- fStart));
                     B2DPoint aSegEnd(cos(fSegEndRad), sin(fSegEndRad));
 
                     aRetval.appendBezierSegment(
@@ -1853,8 +1865,8 @@ namespace basegfx
                         aSegEnd = B2DPoint(cos(fSegEndRad), sin(fSegEndRad));
 
                         aRetval.appendBezierSegment(
-                            aSegStart + (B2DPoint(-aSegStart.getY(), 
aSegStart.getX()) * fScaledKappa),
-                            aSegEnd - (B2DPoint(-aSegEnd.getY(), 
aSegEnd.getX()) * fScaledKappa),
+                            aSegStart + (B2DPoint(-aSegStart.getY(), 
aSegStart.getX()) * fSegmentKappa),
+                            aSegEnd - (B2DPoint(-aSegEnd.getY(), 
aSegEnd.getX()) * fSegmentKappa),
                             aSegEnd);
 
                         nSegment = (nSegment + 1) % nSegments;
@@ -1863,7 +1875,7 @@ namespace basegfx
 
                     // End in this sector
                     const double fSegStartRad(nSegment * fAnglePerSegment);
-                    fFactor = fScaledKappa * ((fEnd - fSegStartRad) / 
fAnglePerSegment);
+                    fFactor= impDistanceBezierPointToControl(fEnd - 
fSegStartRad);
                     aSegEnd = B2DPoint(cos(fEnd), sin(fEnd));
 
                     aRetval.appendBezierSegment(
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to