summaryrefslogtreecommitdiff
path: root/basegfx
diff options
context:
space:
mode:
authorArmin Le Grand (allotropia) <armin.le.grand.extern@allotropia.de>2023-02-17 14:05:59 +0100
committerArmin Le Grand <Armin.Le.Grand@me.com>2023-02-20 09:18:18 +0000
commitac824594c577ab4880177b3411a25297b1d08074 (patch)
tree14169c03f1dce63971f811d7b85870f727b301b2 /basegfx
parent7c9acfe5baef275f07c185c6fedf8b6d62d88637 (diff)
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.Grand@me.com>
Diffstat (limited to 'basegfx')
-rw-r--r--basegfx/source/tools/gradienttools.cxx102
1 files changed, 100 insertions, 2 deletions
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