非零环绕规则是图形学中判断某个区域是在所属区域外面还是内部的一种规则。
简单说一下就是这个样子:对于路径中的任意给定区域,从该区域内部画一条足够长的线段,使此线段的终点完全露在路径范围之外。然后将计数器初始化为0,每当这条线段与路径上的直线或曲线相交时,就改变计数器的值。如果与路径顺时针部分相交的时候,则加1;如果与路径的逆时针部分相交的时候,则减1。如果最终值不是0,那么说明区域在路径的里面。
如上图,一条闭合的路径,围绕成了3个区域,也就是图中的A、B、C(图略丑,凑合着看吧)。
A区域向外引一条线段(绿色的),可以看到与路径的顺时针相交,所以计数器加1,变成了1,而再外面一些是不会相交了,由于1不是0,所以A在路径里面。
同理,B区域引一条线段,我们可以看到和逆时针相交,所以减1,也就是-1,也不会再与路径相交了,由于-1不是0,所以B也在路径的内部。
对于C我们引入一条线段,它2次都与顺时针相交,所以计数为2,也就在区域的内部了。
明白了基本的原理我们看一个代码相关的例子吧。
现有HTML:
1 | <canvas id="canvas">不支持canvas</canvas> |
如果支持HTML5的canvas
的时候会创建一个默认大小为300px*150px
的canvas画板;如果不支持的时候会把canvas当成一个div元素来处理,那么就会显示里面的文字了。
然后我们使用JS来绘制图案:
1 | var canvas = document.getElementById("canvas"); |
由上我们画了2个弧线,顶点都是(150,75)的位置(其实就是canvas的中心),然后半径一个是50,一个是25,都是从0到2π(弧度2π也就是360°),所以我们画的是2个圆形(弧线是从右边开始画弧的)。最后一个参数有意思,如果为true的时候是逆时针绘制,如果是false则是顺时针绘制(默认是false),那么上述路径中,内圆内部向外引一条射线,那么与内圆交叉的地方是逆时针,那么减1,而与外圆相交的地方是顺时针,所以加1,所以最终的结果是0,也就是内圆内部其实是路径的外面,所以绘制出来的结果如下:
如果我们把上述画弧的最后一个参数都去掉的话(使用默认值false),那么效果是怎么样子呢?当然是内圆内部也在路径的内部了(有点绕),如下: