Canvas-2D-非零和奇偶环绕规则

28次阅读

共计 1769 个字符,预计需要花费 5 分钟才能阅读完成。


左为奇偶环绕,右为非零环绕

环境

2D 图形不同系统不同浏览器使用图形库可能都不一样。

  • chrome 使用的是 skia 图形函数库
  • firefox 使用的是 cairo 图形函数库

skia 和 cairo 是对后端(backend)的封装,所以可以跨平台,虽然 chrome 使用的图形库是 skia,但是在不同系统上底层图形库还是可能不一样,比如默认系统:

  • mac os 是核心 Quartz 2D 图形库
  • windows xp 及以下版本底层引擎是使用 GDIGDI+,Windows Vista 后使用 Direct2D 


Windows Vista

canvas 和 svg 里面进行填充渲染,CanvasRenderingContext2D.fill() 就是 Canvas 2D API 根据当前填充的样式,填充当前或已经存在的路径,采用 奇偶或非零环绕规则

奇偶(Even-odd Rule)

奇偶就是 路径包围的区域任意点 P 向外做一条射线,如果相交的边总数是奇数填充,反之不填充

var canvas=document.getElementById("myCanvas");
var context=canvas.getContext("2d");

context.strokeStyle = "rgb(0,0,0)";
context.fillStyle = "rgb(250,0,0)"

context.beginPath();
context.moveTo(100, 0);
context.lineTo(100+Math.cos(Math.PI*3/10)*100, 100+Math.sin(Math.PI*3/10)*100);
context.lineTo(100-Math.cos(Math.PI*1/10)*100, 100-Math.sin(Math.PI*1/10)*100);
context.lineTo(100+Math.cos(Math.PI*1/10)*100, 100-Math.sin(Math.PI*1/10)*100);
context.lineTo(100-Math.cos(Math.PI*3/10)*100, 100+Math.sin(Math.PI*3/10)*100);
context.lineTo(100, 0);
context.fill('evenodd');
context.stroke();
context.closePath();

非零(Nonzero Rule)

非零就是 路径包围的区域任意点 P 向外做一条射线,环绕数为 0,如果相交的边是从左向右环绕数减 1,从右向左环绕数加 1,环绕数不为零填充,反之不填充

var canvas=document.getElementById("myCanvas");
var context=canvas.getContext("2d");

context.strokeStyle = "rgb(0,0,0)";
context.fillStyle = "rgb(250,0,0)"

context.beginPath();
context.moveTo(100, 0);
context.lineTo(100+Math.cos(Math.PI*3/10)*100, 100+Math.sin(Math.PI*3/10)*100);
context.lineTo(100-Math.cos(Math.PI*1/10)*100, 100-Math.sin(Math.PI*1/10)*100);
context.lineTo(100+Math.cos(Math.PI*1/10)*100, 100-Math.sin(Math.PI*1/10)*100);
context.lineTo(100-Math.cos(Math.PI*3/10)*100, 100+Math.sin(Math.PI*3/10)*100);
context.lineTo(100, 0);
context.fill('nonzero');
context.stroke();
context.closePath();

总结

为什么 2 种方式渲染出来的图形不一样?


因为 lineTo 默认按照顺时针,无法像 arc 方法一样控制方向, 奇偶环绕时 2 个相交的边,不填充,非零环绕相交 2 个从左向右的边,是 -2,填充  

正文完
 0