无论是 WPF、UWP 还是 Xamarin、MAUI、WinUI,都有可以绘制任意形状的 Geometry 类型,它支持一种路径标记语法,可以拟合各种形状。同时,SVG 格式使用的也是完全相同的路径语法,你用文本编辑器打开一个 SVG 格式时也会看到这样的字符串。
你只需要阅读本文,即可从零开始了解并最终学会路径标记语法。
示例一开始,我们用一张 SVG 图来看看一个典型的路径字符串是什么样子的
你可以点击上面这张图以单独打开它,然后查看网页源代码来观察它的字符串内容。我这里也贴一份:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
这里,path/@d 里的,就是我们即将学习的路径标记字符串。
XAML 系的路径标记语法与之只有一点点不同。
名称在 SVG 的解释文档中,对此语法的称呼为“SVG Path Syntax”(SVG 路径语法)。在 XAML 系语言中,称其为“Path Markup Syntax”(路径标记语法),官方也称其为“Mini-Language”。
由于 SVG 和 XAML 的路径语法几乎一样,所以学会本文可以直接学会两者的语法。
语法(Syntax)路径标记语法从前往后写下来,遵循“命令-参数-命令-参数-命令-参数-……”这样的要求。让我们再来一个更简单的例子:
1
M 10,100 C 10,300 300,-200 300,100
把解释放进这个字符串的话,是这样:M(命令)10,100(点坐标) C(命令)10,300 300,-200 300,100(三个点坐标)。
在 SVG 路径语法中,一共有如下命令可以使用:
M m L l H h V v C c Q q S s T t A a Z z
额外的,XAML 系的路径标记语法还有一个 F。
看起来很多,但实际上我们可以做一个分类,这样理解起来会更容易一些:
起点M m直线L l、H h、V v贝塞尔曲线C c、Q q、S s、T t椭圆弧A a封闭Z z先来说说一些共性的知识:
一个路径可以由多段组成,用 M m 来指定一个新段的开始大写字母后面跟的参数中,点坐标是绝对坐标;小写字母后面跟的参数中,点坐标是相对坐标如果连续几段都是相同的命令,那么后续可以只写参数而省略命令字符串中间的空格 ` ` 和逗号 , 是用来分隔参数和点的 X、Y 坐标的,可以混用也可以多写下面,我们一个一个说:
F相比于 SVG 来说,F 是 XAML 系路径标记语法唯一一个特有的语法。
带上参数一起,F 只有三种写法:
省略不写F0 表示 EvenOddF1 表示 Nonzero省略不写和 F0 是相同的含义,即 EvenOdd。
SVG 中如果要实现相同的效果,需要设置 path/@style 属性,即style="fill-rule:nonzero;"。
起点和终点M m 移动命令M m(Move,移动)
含义:开始一段新的路径,然后将起点移到 M m 后面的参数中参数:startPoint(起点坐标)示例:M10,100M 后面的 startPoint 参数是绝对点坐标,而 m 后面的 startPoint 参数是相对上一个命令中端点坐标的相对点坐标。
L l H h V v 直线命令L l(Line,直线)
含义:从上一个点开始,连一条直线到此命令的端点参数:endPoint(端点坐标)示例:L100,200H h(Horizontal Line,水平线)
含义:从上一个点开始,连一条水平直线到此命令的横坐标参数:x(横坐标)示例:H100V v(Vertical Line,垂直线)
含义:从上一个点开始,连一条垂直直线到此命令的纵坐标参数:y(纵坐标)示例:V200与前面一样,大写字符后面的坐标和数值是绝对坐标,小写字符后面的坐标和数值是相对坐标。
C c、Q q、S s、T t 贝塞尔曲线命令C c(Cubic Bezier Curve,三次贝塞尔曲线)
含义:从上一个点开始,连一条三次贝塞尔曲线到此命令的端点参数:controlPoint1 controlPoint2 endPoint(控制点坐标1 控制点坐标2 端点坐标)示例:C10,300 300,-200 300,100Q q(Quadratic Bezier Curve,二次贝塞尔曲线)
含义:从上一个点开始,连一条二次贝塞尔曲线到此命令的端点参数:controlPoint endPoint(控制点坐标 端点坐标)示例:Q300,-200 300,100S s(Smooth Cubic Bezier Curve,平滑三次贝塞尔曲线)
含义:从上一个点开始,连一条平滑的三次贝塞尔曲线到此命令的端点,确保在上一个点的曲线是连续的参数:controlPoint2 endPoint(控制点坐标2 端点坐标)示例:S300,-200 300,100所谓“平滑”,即保证曲线在上一个端点处的的曲线连续而没有突变(一次可导)。而平滑的方法,便是将上一个命令在端点处的贝塞尔控制点相对上一个点进行一次镜像。
下面这张图可以说明是如何做到平滑的:
你也可以注意到一个有趣的事情,S s 的参数中只有 controlPoint2 和 endPoint,这是因为 controlPoint 完全是根据上一个点的控制点的镜像来计算得到的,无需传入。
T t(Smooth Quadratic Bezier Curve,平滑二次贝塞尔曲线)
含义:从上一个点开始,连一条平滑的二次贝塞尔曲线到此命令的端点,确保在上一个点的曲线是连续的参数:endPoint(端点坐标)示例:T300,100与 S s 一样,T t 也是确保在上一个点处平滑。控制点的计算方法也是一样对上一个点的控制点进行镜像。由于二次贝塞尔曲线只有一个控制点,所以它是无需传入控制点的,完全是算出来的。
A a 椭圆弧命令A a(Elliptical Arc,椭圆弧)
含义:在上一个点和此命令的端点之间,连一条椭圆弧参数:size rotationAngle isLargeArcFlag sweepDirectionFlag endPoint(包含宽高两个值的尺寸 以度数计量的角度值 大于平角或小于平角标识 顺时针或逆时针标识 端点坐标)示例:A18.621,18.621,0,0,1,18.621,0.000isLargeArcFlag 标识,如果角度大于 180° 则为 1,否则为 0;sweepDirectionFlag 标识,如果顺时针则为 1,如果逆时针则为 0。
Z z 闭合命令含义:如果有此命令,那么图形将闭合形成填充区域;如果没有此命令,那么图形将只有线而不填充没有参数示例:z此命令不区分大小写。
解析在这里挖一个坑,稍后贴出我用“访问者”模式编写的高性能高扩展性的路径语法解析代码。
参考资料
Path Markup Syntax - WPF .NET Framework - Microsoft DocsPaths — SVG 2Paths – SVG 1.1 (Second Edition) 本文会经常更新,请阅读原文: https://blog.walterlv.com/post/path-markup-syntax.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected]) 。