这篇文章发布于 2018年10月3日,星期三,18:58,归类于 Canvas相关, SVG相关。 阅读 38119 次, 今日 12 次 19 条评论
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=8043
本文可全文转载,但需得到原作者书面许可,同时保留原作者和出处,摘要引流则随意。
一、填充有两种规则
只要是路径填充,都有两种规则,nonzero和evenodd,无论是SVG中的路径填充,还是Canvas中的路径填充,如果还有其他和路径相关的技术(甚至设计软件),也离不开这两种填充规则。
换句话说,这是超越各种语言,普世通用的技能点。
下面,看看我能不能用足够精简的语言,尽可能让大家都搞懂这两种路径填充规则。
如果我们用3个点,连成一个三角形,则这两种填充规则没什么区别,如下对比(Canvas语法举例,JS实时渲染,如果无效果,请访问原文)。
nonzero(默认) | evenodd |
---|---|
如果是两个三角形,并且发生重叠,差异就出现了,如下:
nonzero(默认) | evenodd |
---|---|
究竟是如何作用的呢?且看~
二、一切都是交叉点们的选择
填充规则的关键,就是确定复杂路径构成的图形,哪些是内部,哪些是外部。内部则填充,外部则透明。
“nonzero规则”顾名思意就是“非零规则”,用通俗的话讲,就算计算某些东西是不是0
,如果不是0
则内部,填充;如果是0
则外部,不填充。
“evenodd规则”顾名思意就是“奇偶规则”,用通俗的话讲,就算计算某些东西是不是奇数,如果是是奇数则内部,填充;如果是偶数则外部,不填充。
下面关键来了,这里的“计算某些东西”究竟计算的是什么东西呢?
nonzero规则和evenodd规则计算的东西还不一样,nonzero是计算顺时针逆时针数量,evenodd是交叉路径数量。
为了示意更加直观,我们可以把本文示意的三角路径方向和序号标记下,如下表:
nonzero(默认) | evenodd |
---|---|
接下来,高能来了……
我们要判断某一个区域是路径内还是路径外,很简单,在这个区域内任意找一个点,然后以这个点为起点,发射一条无限长的射线,然后——
- 对于nonzero规则:起始值为0,射线会和路径相交,如果路径方向和射线方向形成的是顺时针方向则+1,如果是逆时针方向则-1,最后如果数值为0,则是路径的外部;如果不是0,则是路径的内部,因此被称为“非0规则”。
一图胜千言:
例如上图点A,我们随便发出一条射线,结果经过了路径5和路径2,我们顺着路径前进方向和射线前进方向,可以看到,合并后的运动方向都是逆时针,逆时针方向-1,因此,最后计算值是-2,不是0,因此,是内部,fill时候可以被填充。
再看外部的例子,一图胜千言+1:
点B再发出一条射线,经过两条路径片段,为路径2和路径3,我们顺着路径前进方向和射线前进方向,可以看到,合并后的运动方向一个是逆时针,-1,一个是顺时针,+1,因此,最后的计算值是0,是外部,因此,不被填充。
- 对于evenodd规则:起始值为0,射线会和路径相交,每交叉一条路径,我们计数就+1,最后看我们的总计算数值,如果是奇数,则认为是路径内部,如果是偶数,则认为是路径外部。
一图胜千言+2:
例如上图点A,我们随便发出一条射线,结果经过了路径5和路径2,交叉的路径个数为2,是偶数,因此,属于路径外,不填充。
一图胜千言+3:
点B再发出一条射线,经过路径片段路径2和路径3,交叉的路径个数为2,是偶数,因此,也属于路径外,不填充。
一图胜千言+4:
最后这个点C,发出的射线总共和3个路径交叉,是奇数。因此,属于路径内,填充。
三、啦啦啦,结束语
不知大家搞懂没?
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=8043
(本篇完)
- CSS3 text-fill-color简介及应用展示 (0.386)
- 5分钟快速了解下CSS4 color-adjust属性 (0.386)
- -webkit-box-reflect属性简介及元素镜像倒影实现 (0.143)
- CSS, SVG和canvas分别实现文本文字纹理叠加效果 (0.129)
- CSS paint-order祝大家元旦快乐 (0.129)
- 如何让文字作为CSS背景图片显示? (0.129)
- polyfill、ponyfill、prollyfill傻傻分不清楚 (0.129)
- 致设计师:图标图形制作-路径为王 (0.086)
- 深度掌握SVG路径path的贝塞尔曲线指令 (0.086)
- SVG+JS path等值变化实现CSS3兴叹的图形动画 (0.086)
- CSS届的绘图板CSS Paint API简介 (RANDOM - 0.014)
大佬,请问是如何判断两条线相交的呢
求直线的交点,看这里:https://zengxiaoluan.com/line-line-intersection/
射线与路径5和2相交,合并后是逆时针?怎么理解?
懂了,太骚了
66666
对于“非零规则”
1. 撇开时针去理解:以射线方向分左右,曲线从左向右穿过射线,计数-1;从右向左穿过射线,计数+1
2. 加入时针去理解:以起点为圆心,在相交点处,沿着曲线方向画圆,顺时针方向计数-1;反之+1;(与张老师关于顺/逆时针的定义刚好相反,wiki中对于“非零规则”的定义是:顺时针-1,逆时针+1,但每个人定义顺/逆时针的标准不一样,所以顺时针+1 or -1也不一样。不过张老师这种定义计算的结果最后与按wiki中定义计算的结果是一致的。)
谢谢分享,通俗易懂
更形象一点理解:
~直接打开PS,用钢笔工具画一个有很多交叉的图形
~右键-建立选区,这时候生成的虚线框的内部就是 nozero 的内部
~点击填色,这时候被填色的部分就是 evenodd 的内部
我在sketch的图形上也发现了这两个属性,不知道到底是干嘛用的,看了这篇文章搞明白了。但问题是,确定这两个属性实际解决什么问题呢?
终于搞懂啦!谢谢分享!
想问一下这个有什么用
“顾名思义”,[小纠结]
那个nonzero规则的逆时针、顺时针还是看得头晕啊!不懂。
在交叉线左侧就是逆时针,右侧就是顺时针吧
感谢,懂了!~\(≧◇≦)/~
另外,「换句胡说」-> 「换句话说」
好的,感谢反馈!
顺时针:射线以零点为转动起点,射线方向和路径方向相交后,路径方向在射线方向顺时针转动过的方向(射线以零点为坐标形成的角度)以内。
逆时针:射线以零点为转动起点,射线方向和路径方向相交后,路径方向在射线方向顺时针转动过的方向(射线以零点为坐标形成的角度)以外。
简而言之:当射线和路径方向都以零点为顺时针转动坐标起点,当路径的方向和零点形成的角度大于射线和零点形成的角度则为逆时针,若小于则为顺时针。
谢谢
补充一点,渲染的时候,仅在包含这个图形的方框范围内执行扫描线算法,而且是直接每行每行地异或得到结果的