SVG - 如何将变换矩阵应用于径向渐变?

时间:2018-05-26 16:36:48

标签: svg matrix transform draw radial-gradients

我正在编写一个c ++应用程序,它可以打开几个SVG文件并在屏幕上绘制它们。其中一些包含径向梯度,其中提供了变换矩阵。我需要在执行绘图之前计算要应用的最终梯度值,但是我有一些麻烦。

例如,请考虑以下SVG:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
   xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   version="1.1"
   id="svg2"
   viewBox="0 0 250 250"
   height="250"
   width="250">
  <defs
     id="defs4">
    <linearGradient
       osb:paint="gradient"
       id="linearGradient4162">
      <stop
         id="stop4164"
         offset="0"
         style="stop-color:#d4ca67;stop-opacity:1" />
      <stop
         id="stop4166"
         offset="1"
         style="stop-color:#64caea;stop-opacity:1;" />
    </linearGradient>
    <radialGradient
       gradientUnits="userSpaceOnUse"
       gradientTransform="matrix(0.43766035,0.50852999,-0.28201922,0.24271652,332.30951,640.28863)"
       spreadMethod="reflect"
       r="125.35714"
       fy="938.15851"
       fx="14.381515"
       cy="938.15851"
       cx="14.381515"
       id="radialGradient4172"
       xlink:href="#linearGradient4162" />
  </defs>
  <g
     transform="translate(0,-802.36216)"
     id="layer1">
    <path
       id="rect4136"
       d="m 0.45358449,802.63 250.71427551,0 0,250.3572 -250.71427551,0 z"
       style="opacity:1;fill:url(#radialGradient4172);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
  </g>
</svg>

一旦绘制,该SVG应该给出以下结果:

enter image description here

在我的应用程序中,只要忽略他提供的变换矩阵,我就可以绘制SVG。在这种情况下,我有一个连贯的结果,但当然,不符合预期的结果。

enter image description here

现在我尝试将变换矩阵应用于径向渐变值。我得到了完全不一致的结果。

enter image description here

这是我在c ++代码中尝试做的伪代码,以获得正确的变换梯度值:

Vector2 brushRadius(brush.Radius.Width, brush.Radius.Height);
Vector2 brushCenter(brush.Center.X, brush.Center.Y);
Vector2 brushFocus(brush.Focus.X, brush.Focus.Y);

brushRadius = brush.Matrix.Transform(brushRadius);
brushCenter = brush.Matrix.Transform(brushCenter);
brushFocus  = brush.Matrix.Transform(brushFocus);

brush.m_Radius = Size(brushRadius.X, brushRadius.Y);
brush.m_Center = Point(brushCenter.X, brushCenter.Y);
brush.m_Focus  = Point(brushFocus.X, brushFocus.Y);

显然这不起作用。

那么有人可以向我解释我做错了什么,以及如何将变换矩阵应用于径向渐变值以获得正确的结果?

1 个答案:

答案 0 :(得分:1)

考虑Inkscape在其UI中表示radialGradient的方式:

enter image description here

(我改变了你的例子,所以焦点与中心不同,它显示为中心下方的十字架。)

您可以使用此UI以立即应用gradientTransform的方式操纵渐变,而无需知道其确切参数。您看到的是中心和两个向量,或者,如果您需要,可以定义非简并平行四边形的点。缩放矢量使得它们的长度不同,但它们也是旋转的。虽然在这种情况下它们是垂直的,但它们还可能是倾斜的。

绘制渐变最终需要的是所有三个点的坐标(加上焦点)。这将是八个独立的值,而您当前的定义只设置六个。

设置四个2D坐标在数学上与设置两个加上一些额外的独立值相同(在尝试可能的宽度,高度,旋转和倾斜之后)。这取决于你的绘画方式。表示之间的转换是纯粹的数学问题。但正如你应该从线性代数中知道的那样:你总是需要八个独立的值。