填充路径时所使用的 “非零环绕规则”

  工作繁忙之际,抽了点时间看了下canvas,今天看到了“非零环绕规则”,抱着好奇的心里写了下书上的demo看了看效果,感觉还蛮实用的。

  先简单说说“非零环绕规则”原理(基本摘自书本):如果绘图路径是循环的,或是包含多个相交的子路径,那么canvas的绘图环境变量就必须要判断,当fill()方法被调用时,应该如何对当前路径进行填充。canvas在填充那种互相有交叉路径时就会使用到“非零环绕规则”。“非零环绕规则是这么来判断自我交叉情况的路径的:对于路径中的任意给定的区域,从该区域内部画一条足够长的线段,使此线段的终点完全落在路径范围之外。

  接下来,将计数器初始化为0,然后,每当这条线段与路径上的直线或曲线相交时,就改变计数器的值。(这里是重点)如果是与路径的顺时针部分相交,则加1,如果是与路径的逆时针部分相交,则减1.若计数器的值最终不为0,那么此区域就在路径里面(这里理解了就好说了),在调用fill()方法时,浏览器就会对其进行填充。如果最终值是0,那么此区域就不在路径内部,浏览器也就不会对其进行填充了。

  看到这差不多明白了吧,就是通过区域能够通过的路径的最终计数值来判断该区域是否会进行填充。下面以一个小demo来进行说明。

 1 var canvas=document.getElementById(‘canvas‘);
 2 var context=canvas.getContext(‘2d‘);
 3 function drawTwoArcs(){
 4     context.beginPath();
 5     context.arc(300,190,150,0,Math.PI*2,false); //顺时针
 6     context.arc(300,190,100,0,Math.PI*2,true); //逆时针
 7
 8     context.fill();
 9     context.stroke();
10 }
11
12 function draw(){
13     context.clearRect(0,0,context.canvas.width,context.canvas.height);
14     context.save();
15     context.shadowColor="rgba(0,0,0,0.8)";
16     context.shadowOffsetX=12;
17     context.shadowOffsetY=12;
18     context.shadowBlur=15;
19
20     drawTwoArcs();
21     context.restore();
22 }
23
24 context.fillStyle="rgba(100,140,230,0.5)";
25 context.strokeStyle=context.fillStyle;
26 draw();

  该demo中绘制了2个同心圆,内部的圆以顺时针绘制,外部的圆以逆时针绘制,程序最后对外层圆填充时,浏览器就会运用”非零环绕规则“进行填充判断。我们从里层圆内部引一条直线出来,它会与路径相交2次,两个圆的绘制方向不同,所以从里层的圆引出的线最终计数值为0,里层的圆就不会进行填充,同理可以得到外层圆与里层圆之间的部分会得到填充,最终就产生了一种剪纸图案的效果(个人感觉不怎么像剪纸,不过效果还是有点漂亮的)。

  效果图:

时间: 2024-11-10 07:02:28

填充路径时所使用的 “非零环绕规则”的相关文章

填充路径时使用的非零环绕规则

如果当前路径是循环的,或者包含多个相交的子路径,那么Canvas的绘图环境变量就必须判断,当fill()方法被调用时,应该如何对当前路径进行填充. Canvas在填充互相有交叉的路径时,使用非零环绕规则 非零环绕 对于路径中的任意给定区域,从该区域内部画一条足够长的线段,使此线段的终点完全落在路径范围之外. 接下来将计数器初始化为0,然后,每当这条线段与路径上的直线或曲线相交时,就改变计算器的值.如果是与路径的顺时针部分相交,则加1,如果与路径的逆时针相交,则减1. 若计算器的最终值不是0,那么

Canvas中的非零环绕规则原理

非零环绕规则:对于路径中指定范围区域,从该区域内部画一条足够长的线段,使此线段的完全落在路径范围之外. 非零环绕规则计数器:然后,将计数器初始化为0,每当这个线段与路径上的直线或曲线相交时,就改变计数器的值,如果是与路径顺时针相交时,那么计数器就加1, 如果是与路径逆时针相交时,那么计数器就减1.如果计数器始终不为0,那么此区域就在路径范围里面,在调用fill()方法时,浏览器就会对其进行填充.如果最终值是0,那么此区域就不在路径范围内,浏览器就不会对其进行填充. 从上图中看第一条线段:根据非零

Canvas中的非零环绕

先上图 当要填充图形时,必须区分开哪些部分是覆盖的,哪些是空的,根据绘制的方向可以判断出来 非零环绕规则:对于路径中指定范围区域,从该区域内部画一条足够长的线段,使此线段的完全落在路径范围之外. 非零环绕规则计数器:然后,将计数器初始化为0,每当这个线段与路径上的直线或曲线相交时,就改变计数器的值,如果是与路径顺时针相交时,那么计数器就加1, 如果是与路径逆时针相交时,那么计数器就减1.如果计数器始终不为0,那么此区域就在路径范围里面,在调用fill()方法时,浏览器就会对其进行填充.如果最终值

Canvas中的非零围绕规则原理

非零围绕规则:对于路径中指定范围区域,从该区域内部画一条足够长的线段.使此线段的全然落在路径范围之外. 非零围绕规则计数器:然后,将计数器初始化为0,每当这个线段与路径上的直线或曲线相交时,就改变计数器的值,假设是与路径顺时针相交时.那么计数器就加1, 假设是与路径逆时针相交时.那么计数器就减1.假设计数器始终不为0,那么此区域就在路径范围里面,在调用fill()方法时,浏览器就会对其进行填充.假设终于值是0,那么此区域就不在路径范围内,浏览器就不会对其进行填充. 从上图中看第一条线段:依据非零

非零缠绕规则和奇偶规则

在图形学中判断一个点是否在多边形内,若多边形不是自相交的,那么可以简单的判断这个点在多边形内部还是外部:若多边形是自相交的,那么就需要根据非零环绕数规则和奇-偶规则判断. 判断多边形是否是自相交的:多边形在平面内除顶点外还有其他公共点 内-外测试    不自交的多边形:多边形仅在顶点处连接,而在平面内没有其他公共点,此时可以直接划分内-外部分.    自相交的多边形:多边形在平面内除顶点外还有其他公共点,此时划分内-外部分需要采用以下的方法. (1)奇-偶规则(Odd-even Rule):奇数

canvas填充规则,非零环绕

1.看一块区域是否填充 2.从这个区域拉一条直线 3,看和这条直线相交的轨迹 4.如果顺时针轨迹+1 5.如果逆时针轨迹-1 6.所有轨迹的值计算出来 7.如果是非0,那么填充 8.如果是0那么不填充 原文地址:https://www.cnblogs.com/Yanss/p/10419786.html

n!最右非零数字

n!最右非零数字 注此文大部分来自luoyuchu的blog + ##Description: 给出正整数N(可能有前导0),请求出N!最右非零的数位的值 + ##Range: n<=10^100 + HDU1066 弱化问题USACO 3.2.1 以前做USACO暴力水过了 这是多么的愚昧于是我去学习了一下 考虑虑到末位的0 是由于 2 * 5 这样的运算而产生的,那么我们把2与5成对的剔除就不会出现精度问题了? 其实问题还可以继续深入思考.我们考虑在 10^1000 下如何解决问题 我们考虑

C#中下限非零的数组解析

谈到数组时,当被问及数组是从什么数开始时,估计大部分程序员都会直接说出数组当然是从0开始的.这个回答当然没有错,现在我们就来了解一下C#中的下限非0的数组. 首先看一下数组的相关介绍: 1.数组:是允许将多个数据项当作一个集合来处理的机制. 2.数组的分类:在CLR中,数组可分为一维数组,多维数组,交错数组. 3.数组的类型:由于所有的数组都是继承自System.Array这个抽象类型,而这个类型又是继承自System.Object,这就说明数组是引用类型. 在创建数组时,除了有数组元素,数组对

Keil MDK下如何设置非零初始化变量(转)

源:Keil MDK下如何设置非零初始化变量 一些工控产品,当系统复位后(非上电复位),可能要求保持住复位前RAM中的数据,用来快速恢复现场,或者不至于因瞬间复位而重启现场设备.而keil mdk在默认情况下,任何形式的复位都会将RAM区的非初始化变量数据清零.如何设置非初始化数据变量不被零初始化,这是本篇文章所要探讨的. 在给出方法之前,先来了解一下代码和数据的存放规则.属性,以及复位后为何默认非初始化变量所在RAM都被初始化为零了呢. 什么是初始化数据变量,什么又是非初始化数据变量?(因为我