搞懂SVG/Canvas中nonzero和evenodd填充規則
這篇文章釋出於 2018年10月3日,星期三,18:58,歸類於Canvas相關,SVG相關。閱讀 29 次, 今日 25 次
byzhangxinxu fromofollow,noindex" target="_blank">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
(本篇完)