Swift中如何填充未闭合贝塞尔路径的环路部分?
如何仅填充NSBezierPath的环路部分(而非整个未闭合路径的覆盖区域)
嘿,我明白你遇到的问题了——用未闭合的NSBezierPath填充时,Core Graphics默认会自动把路径的起点和终点连接起来,形成一个大的闭合区域,导致填充范围和你想要的环路部分完全不符。别担心,这里有几个实用的解决方案,你可以根据自己的路径结构来选择:
方案一:调整填充的缠绕规则(最适合交叉路径)
Core Graphics的填充行为由缠绕规则决定,默认的non-zero winding rule会把所有被路径包围的区域都填充,而切换到even-odd winding rule后,只会填充被路径奇数次包围的区域,刚好适合处理交叉形成的环路。
你只需要在填充路径时修改规则即可,修改后的代码片段如下:
UIGraphicsBeginImageContext(board.size) if let context = UIGraphicsGetCurrentContext() { if let path = snake.path { context.setShouldAntialias(false) let transformedPath = CGMutablePath() transformedPath.addPath(path, transform: transform) context.addPath(transformedPath) // 设置填充颜色(根据你的需求调整) context.setFillColor(UIColor.yourFillColor.cgColor) // 关键:使用even-odd缠绕规则填充 context.fillPath(using: .evenOdd) } } UIGraphicsEndImageContext()
方案二:手动提取闭合子路径(适合明确包含环路的路径)
如果你的路径是由多个线段组成,其中明确包含闭合的环路子路径,你可以遍历路径的元素,把闭合的子路径单独提取出来填充,这样就能精准控制只填充环路部分。
示例代码如下:
UIGraphicsBeginImageContext(board.size) if let context = UIGraphicsGetCurrentContext(), let cgPath = snake.path?.cgPath { context.setShouldAntialias(false) context.setFillColor(UIColor.yourFillColor.cgColor) var isSubpathClosed = false var currentSubpath = CGMutablePath() // 遍历CGPath的每个元素 cgPath.applyWithBlock { element in switch element.type { case .moveToPoint: // 如果之前的子路径是闭合的,先填充它 if isSubpathClosed { context.addPath(currentSubpath) context.fillPath() currentSubpath = CGMutablePath() isSubpathClosed = false } currentSubpath.move(to: element.points.pointee) case .addLineToPoint: currentSubpath.addLine(to: element.points.pointee) case .addQuadCurveToPoint: let points = element.points currentSubpath.addQuadCurve(to: points[1], control: points[0]) case .addCurveToPoint: let points = element.points currentSubpath.addCurve(to: points[2], control1: points[0], control2: points[1]) case .closeSubpath: currentSubpath.closeSubpath() isSubpathClosed = true @unknown default: break } } // 处理最后一个闭合的子路径 if isSubpathClosed { context.addPath(currentSubpath) context.fillPath() } } UIGraphicsEndImageContext()
方案三:描边路径后提取环路(适合线条交叉形成的环路)
如果你的未闭合路径是通过线条交叉形成的环路,可以先把原路径描边成一个闭合的区域,再用even-odd规则填充,这样就能得到环路的填充效果。
示例代码如下:
UIGraphicsBeginImageContext(board.size) if let context = UIGraphicsGetCurrentContext() { if let path = snake.path { context.setShouldAntialias(false) let transformedPath = CGMutablePath() transformedPath.addPath(path, transform: transform) // 将原路径描边成闭合区域(宽度根据你的线条粗细调整) let strokedPath = transformedPath.copy( strokingWithWidth: 2.0, lineCap: .butt, lineJoin: .miter, miterLimit: 10 ) context.addPath(strokedPath) context.setFillColor(UIColor.yourFillColor.cgColor) context.fillPath(using: .evenOdd) } } UIGraphicsEndImageContext()
总结
- 如果你的路径是交叉形成的环路,优先尝试方案一,最简单高效;
- 如果路径里有明确的闭合子路径,方案二能精准控制填充区域;
- 如果是线条交叉形成的环路,方案三可以把线条转化为闭合区域再填充。
内容的提问来源于stack exchange,提问作者Connor Yass
相关产品推荐
相关产品推荐

