basegfx/source/tools/gradienttools.cxx |  102 ++++++++++++++++++++++++++++++++-
 1 file changed, 100 insertions(+), 2 deletions(-)

New commits:
commit ac824594c577ab4880177b3411a25297b1d08074
Author:     Armin Le Grand (allotropia) <armin.le.grand.ext...@allotropia.de>
AuthorDate: Fri Feb 17 14:05:59 2023 +0100
Commit:     Armin Le Grand <armin.le.gr...@me.com>
CommitDate: Mon Feb 20 09:18:18 2023 +0000

    MCGR: Correct GradientElliptical & GradientRect
    
    The visualizations when using the texturing methods
    modifyBColor/get*GradientAlpha were both not correct
    since they did not apply the aspect ratio.
    
    I corrected both where GradientRect is correct, but
    GradientElliptical is close and may have small
    divergencies.
    
    Change-Id: I6bcc07ec7cd4cdeb7863b51b20db3a7dd5afc41c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147218
    Tested-by: Jenkins
    Reviewed-by: Armin Le Grand <armin.le.gr...@me.com>

diff --git a/basegfx/source/tools/gradienttools.cxx 
b/basegfx/source/tools/gradienttools.cxx
index 3f2480c82e84..b3bb18f918da 100644
--- a/basegfx/source/tools/gradienttools.cxx
+++ b/basegfx/source/tools/gradienttools.cxx
@@ -451,7 +451,38 @@ namespace basegfx
 
         double getEllipticalGradientAlpha(const B2DPoint& rUV, const 
ODFGradientInfo& rGradInfo)
         {
-            return getRadialGradientAlpha(rUV, rGradInfo); // only matrix 
setup differs
+            const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV);
+
+            if(aCoor.getX() < -1.0 || aCoor.getX() > 1.0 || aCoor.getY() < 
-1.0 || aCoor.getY() > 1.0)
+            {
+                return 0.0;
+            }
+
+            double fAspectRatio(rGradInfo.getAspectRatio());
+            double t(1.0);
+
+            // MCGR: Similar to getRectangularGradientAlpha (please
+            // see there) we need to use aspect ratio here. Due to
+            // initEllipticalGradientInfo using M_SQRT2 to make this
+            // gradient look 'nicer' this correciton seems not 100%
+            // correct, but is close enough for now
+            if(fAspectRatio > 1.0)
+            {
+                t = 1.0 - std::hypot(aCoor.getX() / fAspectRatio, 
aCoor.getY());
+            }
+            else if(fAspectRatio > 0.0)
+            {
+                t = 1.0 - std::hypot(aCoor.getX(), aCoor.getY() * 
fAspectRatio);
+            }
+
+            const sal_uInt32 nSteps(rGradInfo.getRequestedSteps());
+
+            if(nSteps && t < 1.0)
+            {
+                return floor(t * nSteps) / double(nSteps - 1);
+            }
+
+            return t;
         }
 
         double getSquareGradientAlpha(const B2DPoint& rUV, const 
ODFGradientInfo& rGradInfo)
@@ -484,7 +515,74 @@ namespace basegfx
 
         double getRectangularGradientAlpha(const B2DPoint& rUV, const 
ODFGradientInfo& rGradInfo)
         {
-            return getSquareGradientAlpha(rUV, rGradInfo); // only matrix 
setup differs
+            const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV);
+            double fAbsX(fabs(aCoor.getX()));
+
+            if(fAbsX >= 1.0)
+            {
+                return 0.0;
+            }
+
+            double fAbsY(fabs(aCoor.getY()));
+
+            if(fAbsY >= 1.0)
+            {
+                return 0.0;
+            }
+
+            // MCGR: Visualiations using the texturing method for
+            // displaying gradients (getBackTextureTransform is
+            // involved) show wrong results for GradientElliptical
+            // and GradientRect, this can be best seen when using
+            // less steps, e.g. just four. This thus has influence
+            // on cppcanvas (slideshow) and 3D textures, so needs
+            // to be corrected.
+            // Missing is to use the aspect ratio of the object
+            // in this [-1, -1, 1, 1] unified coordinate space
+            // after getBackTextureTransform is applied. Optically
+            // in the larger direction of the texturing the color
+            // step distances are too big *because* we are in that
+            // unit range now.
+            // To correct that, a kind of 'limo stretching' needs to
+            // be applied, adding space around the center
+            // proportional to the aspect ratio, so the intuitive
+            // idea would be to do
+            //
+            // fAbsX' = ((fAspectRatio - 1) + fAbsX) / fAspectRatio
+            //
+            // which scales from the center. This does not work, and
+            // after some thoughts it's clear why: It's not the
+            // position that needs to be moved (this cannot be
+            // changed), but the position *before* that scale has
+            // to be determined to get the correct, shifted color
+            // for the already 'new' position. Thus, turn around
+            // the expression as
+            //
+            // fAbsX' * fAspectRatio = fAspectRatio - 1 + fAbsX
+            // fAbsX' * fAspectRatio - fAspectRatio + 1 = fAbsX
+            // fAbsX = (fAbsX' - 1) * fAspectRatio + 1
+            //
+            // This works and can even be simply adapted for
+            // fAspectRatio < 1.0 aka vertical is bigger.
+            double fAspectRatio(rGradInfo.getAspectRatio());
+            if(fAspectRatio > 1.0)
+            {
+                fAbsX = ((fAbsX - 1) * fAspectRatio) + 1;
+            }
+            else if(fAspectRatio > 0.0)
+            {
+                fAbsY = ((fAbsY - 1) / fAspectRatio) + 1;
+            }
+
+            const double t(1.0 - std::max(fAbsX, fAbsY));
+            const sal_uInt32 nSteps(rGradInfo.getRequestedSteps());
+
+            if(nSteps && t < 1.0)
+            {
+                return floor(t * nSteps) / double(nSteps - 1);
+            }
+
+            return t;
         }
     } // namespace utils
 } // namespace basegfx

Reply via email to