先上代码
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="300px" height="300px">
<polygon points="100,0 160,180 10,60 190,60 40,180" style="fill:red;stroke:black;stroke-width:1;fill-rule:nonzero"/>
</svg>
画出来是这样的
把fill-rule改成evenodd后,是这样的
先看看官方文档里面fill-rule两个属性的解释,
nonzero—这个规则通过从canvas上的某个点往任一方向绘制射线到无穷远,然后检查图形的线段和射线相交的点,来确定“内部区域”。从0
开始计数,每次路径线段是从左到右穿过射线就加一,从右到左的就减一。通过计算交叉点,如果结果是0
,则这个点在路径外边,不然,就是在里边。
evenodd—这个规则通过从canvas上某个点往任一方向绘制射线到无穷远,然后计算给定图形上线段路径和该射线交叉点的数量。如果这个数是奇数,那么该点在图形内部;如果是偶数,该点在图形外部。
一看两幅图,你可能会有两个疑问,这些线段的箭头是什么?两组图形的第三幅图为什么是一样的?其实这些线段的方向是由我们给出的坐标的顺序决定的,points="100,0 160,180 10,60 190,60 40,180",起始点是最上方的点,然后是右下,最左边,最右边,再到左下。把这些点按顺序连起来就变成了五角星。
先在图上随机取几个点,蓝色射线的起始点就是随机的点,射线1,2,3,4穿过的图形线段数分别是1,2,3,4,如图
先看nozero时,怎么判断点是否在内部区域。射线1和图形线段只有一个交点,为从左到右,所以结果是1,判定为内部区域;射线2有两个交点,都是从左到右,结果是2,内部区域;射线3有三个交点,两个从左到右,一个从右到左,结果是1,内部区域;射线4有四个交点,两个从左到右,两个从右到左,结果是0,所以是外部区域。
evenodd时,只判断交点个数,所以1,3都是内部区域,2,4都是外部区域。
结果就很清楚啦,那两组图的第三个图为什么是一样的,也一目了然啦,在圆环内的点,与图形线段的交点有两个,一左进右出,一右进左出,所以两种判定方式下都是外部区域。
因为方向没固定,所以从一个点可以作出无数条射线,那会不会出现不同射线有不同结果的情况呢?我尝试去掉了一个角
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="300px" height="300px">
<polygon points="135,104 100,0 40,180 190,60 10,60 100,132" style="fill:red;stroke:black;stroke-width:1;fill-rule:evenodd;"/>
</svg>
结果是这样的,我认为这里右下角的线段其实应该算是两条,画图时两次经过了这个地方,所以应该不能算一条线段,而是两条,所以按上面讲的规则,还是没错。暂时想不到会产生不一样结果射线的点。
学到这里,仍存在两个问题:
1、是否有某些点画出来的射线会得到不同的结果,而最终的结果又是根据哪个?
2、简单的图形容易判断,那复杂的图形呢?怎么才能直观的理解这两个规则?比如下图:
以上内容皆为个人理解,若有错误,请指教。谢谢。