SVG - 如何将渐变变换矩阵应用于线性渐变画笔?

SVG - How to apply a gradient transform matrix to a linear gradient brush?

我正在用 C++ 语言编写一个 SVG 查看器应用程序。我实际上在几个我无法弄清楚的 SVG 文件中遇到了转换问题。

考虑以下 SVG 文件:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg9686" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="90mm" width="145mm" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 145 90" xmlns:dc="http://purl.org/dc/elements/1.1/">
 <defs id="defs9680">
  <linearGradient id="linearGradient6593-0" gradientUnits="userSpaceOnUse" x1="74.658" y1="-398.92" x2="75.519" y2="-485.7" gradientTransform="matrix(1.0069 0 0 1.19 1.4571 709.77)">
   <stop id="stop6595" stop-color="#be245a" offset="0"/>
   <stop id="stop6600" stop-color="#e46e6f" offset=".48408"/>
   <stop id="stop6597" stop-color="#f1a769" offset="1"/>
  </linearGradient>
 </defs>
 <g id="layer1" transform="translate(-7.631 -139.36)">
  <rect id="rect3690-4-2-09-4-2-8-0" height="90" width="145" y="139.36" x="7.631" fill="url(#linearGradient6593-0)"/>
 </g>
</svg>

这基本上是一个用渐变画笔填充的矩形,从橙色到洋红色。矩形大小为 90x145,在应用所有变换后位于坐标 [0, 0]。

如果我很好地理解了理论,要正确绘制矩形,我应该处理以下步骤:

  1. 在本地文档坐标系中计算由 x1、y1、x2 和 y2 值给定的渐变画笔边界框。这应该通过将给定的梯度变换矩阵应用于从 x1、y1、x2 和 y2
  2. 计算的点来完成
  3. 由于渐变单位声明为"user space on use",根据线性渐变标签值和转换后的边界框计算画笔
  4. 变换矩形坐标进行填充,也放到文档坐标系中
  5. 使用之前创建的画笔,在变换后的坐标处绘制矩形

应用上述过程,我预计会得到以下结果:

但我得到了这个结果:

如果我手动更改上述源文件中的所有值,以删除所有转换并应用文档坐标中的所有值,则线性渐变会正确填充到我的矩形中。因此,如果有人能向我解释,我将非常感激

  1. 我在我的过程中做错了什么?
  2. 我应该如何计算线性渐变值?
  3. 我应该如何将梯度矩阵应用于给定值? (即我预计将矩阵应用于值应该在文档系统坐标中转换它们,因此转换后的值应该大致给出 x1 = 0、y1 = 0、x2 = 90 和 y2 = 145 作为结果,但事实并非如此)

注意欢迎以数学形式进行演示

首先,我认为对渐变使用术语 "bounding box" 没有帮助。四个值 x1, x2, y1, y2 描述了一个 vector,渐变停止匹配到它,并且梯度法线垂直于它(在应用任何变换之前)。 "box" 与梯度属性没有任何有意义的关系。

梯度向量可以可视化为线元素

<line x1="74.658" y1="-398.92" x2="75.519" y2="-485.7" />

第一步是申请gradientTransform="matrix(1.0069 0 0 1.19 1.4571 709.77)"。结果线将绘制为

<line x1="76.6302" y1="235.055" x2="77.4972" y2="131.787" />

(由于变换没有引入倾斜,梯度法线仍然垂直于那条线。)

此时,渐变应用于矩形在其本地坐标系

<rect width="145" height="90" x="7.631" y="139.36"/>
<line x1="76.6302" y1="235.055" x2="77.4972" y2="131.787" />

只有在那之后,最终的 transform="translate(-7.631 -139.36)" 才同时应用于矩形和矢量:

<rect width="145" height="90" x="7.631" y="139.36"/>
<line x1="70" y1="95.7" x2="69.87" y2="-7.57" />

请注意,如果变换直接应用于矩形而不是封闭组,这甚至是正确的。将转换应用于元素始终是最后执行的操作。

我认为您出错的地方是在对矩形应用变换后将 userSpaceOnUse 解释为 最终 坐标系。但它是 coordinate system

in place at the time when the gradient element is referenced,

因此 进一步转换之前。