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]。
如果我很好地理解了理论,要正确绘制矩形,我应该处理以下步骤:
- 在本地文档坐标系中计算由 x1、y1、x2 和 y2 值给定的渐变画笔边界框。这应该通过将给定的梯度变换矩阵应用于从 x1、y1、x2 和 y2
计算的点来完成
- 由于渐变单位声明为"user space on use",根据线性渐变标签值和转换后的边界框计算画笔
- 变换矩形坐标进行填充,也放到文档坐标系中
- 使用之前创建的画笔,在变换后的坐标处绘制矩形
应用上述过程,我预计会得到以下结果:
但我得到了这个结果:
如果我手动更改上述源文件中的所有值,以删除所有转换并应用文档坐标中的所有值,则线性渐变会正确填充到我的矩形中。因此,如果有人能向我解释,我将非常感激
- 我在我的过程中做错了什么?
- 我应该如何计算线性渐变值?
- 我应该如何将梯度矩阵应用于给定值? (即我预计将矩阵应用于值应该在文档系统坐标中转换它们,因此转换后的值应该大致给出 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,
因此 在 进一步转换之前。
我正在用 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]。
如果我很好地理解了理论,要正确绘制矩形,我应该处理以下步骤:
- 在本地文档坐标系中计算由 x1、y1、x2 和 y2 值给定的渐变画笔边界框。这应该通过将给定的梯度变换矩阵应用于从 x1、y1、x2 和 y2 计算的点来完成
- 由于渐变单位声明为"user space on use",根据线性渐变标签值和转换后的边界框计算画笔
- 变换矩形坐标进行填充,也放到文档坐标系中
- 使用之前创建的画笔,在变换后的坐标处绘制矩形
应用上述过程,我预计会得到以下结果:
但我得到了这个结果:
如果我手动更改上述源文件中的所有值,以删除所有转换并应用文档坐标中的所有值,则线性渐变会正确填充到我的矩形中。因此,如果有人能向我解释,我将非常感激
- 我在我的过程中做错了什么?
- 我应该如何计算线性渐变值?
- 我应该如何将梯度矩阵应用于给定值? (即我预计将矩阵应用于值应该在文档系统坐标中转换它们,因此转换后的值应该大致给出 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,
因此 在 进一步转换之前。