Winding Rules 缠绕规则

栏目: IOS · 发布时间: 5年前

内容简介:在实现一个镂空的效果时,发下路径的方向,会影响最终实现的效果,所以进一步研究了一下。填充路径所包含的区域时,会通过缠绕规则来判断需要填充的区域。通过给定区域内的任意一点到路径外画一条射线,根据与路径的交叉数判断点是否在区域内。缠绕规则:

在实现一个镂空的效果时,发下路径的方向,会影响最终实现的效果,所以进一步研究了一下。

填充路径所包含的区域时,会通过缠绕规则来判断需要填充的区域。通过给定区域内的任意一点到路径外画一条射线,根据与路径的交叉数判断点是否在区域内。

缠绕规则:

  • NSNonZeroWindingRule:非零缠绕。射线从左到右每交叉路径一次+1,从右到左每交叉一次-1。如果最终交叉数为0,则该点在路径之外;如果交叉数不为0,则在路径之内。默认缠绕规则。

  • NSEvenOddWindingRule:奇偶缠绕。计算射线与路径的交叉总数,如果为偶数,则在路径之外;如果为奇数,则在路径之内,需要填充。

填充操作适用于开放式路径和闭合路径。开放式路径会从路径的最后一个点到第一个点创建一个隐式的线(不渲染),来闭合路径。

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Paths/Paths.html#//apple_ref/doc/uid/TP40003290-CH206-BAJIJJGD 中的 Winding Rules中:

When you fill a partial subpath, NSBezierPath closes it for you automatically by creating an implicit (non-rendered) line from the first to the last point of the subpath.

文档中描述是从第一个点到最后一个点,但是根据分析与文档上的图以及实验,图与结果相同,但是描述错误,下面会详细介绍。如果是我理解错误,恳请指出。

本文demo

闭合路径

1. 非零缠绕:外边框和内边框同一方向

    CGRect aRect = CGRectMake(100, 100, 200, 200);
    UIBezierPath * aPath = [UIBezierPath bezierPathWithRect:aRect];
    CGRect bRect = CGRectInset(aRect, 50, 50);
    UIBezierPath * bPath = [UIBezierPath bezierPathWithRect:bRect];
    
    [aPath appendPath:bPath];
    
    CAShapeLayer * shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = aPath.CGPath;
    shapeLayer.fillColor = [UIColor yellowColor].CGColor;
    
    [self.view.layer addSublayer:shapeLayer];

Winding Rules 缠绕规则

内部的点向外画射线,由于两个贝塞尔曲线是同向,射线由右至左跨过路径两次,aRect 以内的所有的点的射线交叉数只有两种情况:0-1=-1,或者0-1-1=-2。都不为0,所以内部的点都在路径之内,需要渲染。

2. 非零缠绕:内边框与外边框反向

// - (UIBezierPath *)bezierPathByReversingPath;  将路径翻转。
// 上面代码只需要修改 bPath
UIBezierPath * bPath = [[UIBezierPath bezierPathWithRect:bRect] bezierPathByReversingPath];

Winding Rules 缠绕规则

分为两种情况:

  • bPath 以内的点的射线与路径交叉只有一种:0+1-1=0,因此 bPath 内部的点都在路径最终路径之外,bPath 以内的点不需要渲染。

  • bPath 以外 aPath 以内的点的射线与路径交叉有两种:0-1=-1,或者0+1+1-1=1。两种情况都不为0,所以在路径之内,需要渲染。

奇偶缠绕规则

奇偶缠绕规则下,与内外路径方向无影响。默认 fillRule 为非零,添加如下代码。

shapeLayer.fillRule = kCAFillRuleEvenOdd;

只判断射线与路径的交叉,所以有两种情况:

  • bRect内部的点,射线与路径的交叉有两个,为偶数,所以不在范围内,不需要渲染。

  • bRect之外aRect以内,射线与路径的交叉数可能为1或3,为奇数,所以需要渲染。

开放式路径

盗取苹果文档的图来分析一下,图 c、d 中的射线,按照从上到下从 左->右 命名为 p1,p2,p3。

Winding Rules 缠绕规则

非零缠绕规则下 图c:

  • p1 从 左->右 穿过隐式路径,在从 左->右 穿过路径,,0+1+1=2,在路径之内,需要渲染。

  • p2 先是从 左->右 穿过路径,再从 右->左 穿过,0+1-1=0,不在路径之内,不需要渲染。

  • p3 两次从 左->右 穿过路径,0+1+1=2,在路径之内,需要渲染。

这里分析一下隐式线的方向问题,修改一下 p2 的方向为垂直向上。

  • 隐式线的方向是 start->end,首先从 右->左 穿过路径,然后还是从 右->左 穿过隐式线,0-1-1=-2,不为0,应该是属于路径之内,需要渲染的,与原结果冲突。

  • 隐式线的方向是 end->start,首先从 右->左 穿过路径,然后从 左->右 穿过隐式线,0-1+1=0,为0不在路径内,不需要渲染,与原结果相同。

奇偶缠绕规则下 图d

  • p1 穿过隐式线和一次路径,共两次,偶数,不在范围内,不会渲染。

  • p2和p3 穿过两次路径,共两次,偶数,不在范围内,不会渲染。

作者:忆思梦

链接:https://www.jianshu.com/p/dcf4140536bb


以上所述就是小编给大家介绍的《Winding Rules 缠绕规则》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

C++ Primer 中文版(第 5 版)

C++ Primer 中文版(第 5 版)

[美] Stanley B. Lippman、[美] Josée Lajoie、[美] Barbara E. Moo / 王刚、杨巨峰 / 电子工业出版社 / 2013-9-1 / CNY 128.00

这本久负盛名的 C++经典教程,时隔八年之久,终迎来史无前例的重大升级。除令全球无数程序员从中受益,甚至为之迷醉的——C++ 大师 Stanley B. Lippman 的丰富实践经验,C++标准委员会原负责人 Josée Lajoie 对C++标准的深入理解,以及C++ 先驱 Barbara E. Moo 在 C++教学方面的真知灼见外,更是基于全新的 C++11标准进行了全面而彻底的内容更新。......一起来看看 《C++ Primer 中文版(第 5 版)》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具