我有一个应用程序,我在其中获取 UIBezierPath 并通过一系列appendPath:调用将其用作画笔。经过几次操作后,如果画笔形状非常复杂,内存就会耗尽,应用程序就会停止运行。我真正想做的是一个完整的联合,就像 Paint Code 所做的那样,但我找不到任何方法来做到这一点。
我将如何联合两个或多个 UIBezierPaths?
编辑:
这是我想要动态实现的视觉效果。
在 Paint Code 中,您采用两条路径并将它们重叠,如下所示:
但是我想将它们合并/联合成一个新的单一路径,例如:
请注意,在 Paint Code 的底部面板中,现在有一个单一形状的代码,这就是我希望能够通过可能 1000 个原始路径以编程方式获得的代码。
通过遵循 Core Graphics 的 2 个概念,您可以轻松获得想要的结果:-
i)CGBlendMode ii)OverLap2Layer
混合模式告诉上下文如何将新内容应用到自身。它们决定像素数据如何进行数字混合。
class UnionUIBezierPaths : UIView {
var firstBeizerPath:UIImage!
var secondBeizerPath:UIImage!
override func draw(_ rect: CGRect) {
super.draw(rect)
firstBeizerPath = drawOverLapPath(firstBeizerpath: drawCircle(), secondBeizerPath: polygon())
secondBeizerPath = drawOverLapPath(firstBeizerpath: polygon(), secondBeizerPath: drawCircle())
let image = UIImage().overLap2Layer(firstLayer:firstBeizerPath , secondLayer:secondBeizerPath)
}
func drawCircle() -> UIBezierPath {
let path = UIBezierPath(ovalIn: CGRect(x: 40, y: 120, width: 100, height: 100) )
return path
}
func polygon() -> UIBezierPath {
let beizerPath = UIBezierPath()
beizerPath.move(to: CGPoint(x: 100, y: 10) )
beizerPath.addLine(to: CGPoint(x: 200.0, y: 40.0) )
beizerPath.addLine(to: CGPoint(x: 160, y: 140) )
beizerPath.addLine(to: CGPoint(x: 40, y: 140) )
beizerPath.addLine(to: CGPoint(x: 0, y: 40) )
beizerPath.close()
return beizerPath
}
func drawOverLapPath(firstBeizerpath:UIBezierPath ,secondBeizerPath:UIBezierPath ) -> UIImage {
UIGraphicsBeginImageContext(self.frame.size)
let firstpath = firstBeizerpath
UIColor.white.setFill()
UIColor.black.setStroke()
firstpath.stroke()
firstpath.fill()
// sourceAtop = 20
let mode = CGBlendMode(rawValue:20)
UIGraphicsGetCurrentContext()!.setBlendMode(mode!)
let secondPath = secondBeizerPath
UIColor.white.setFill()
UIColor.white.setStroke()
secondPath.fill()
secondPath.stroke()
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
func drawImage(image1:UIImage , secondImage:UIImage ) ->UIImage
{
UIGraphicsBeginImageContext(self.frame.size)
image1.draw(in: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height) )
secondImage.draw(in: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height) )
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
//OverLap2Layer
extension UIImage {
func overLap2Layer(firstLayer:UIImage , secondLayer:UIImage ) -> UIImage {
UIGraphicsBeginImageContext(firstLayer.size)
firstLayer.draw(in: CGRect(x: 0, y: 0, width: firstLayer.size.width, height: firstLayer.size.height) )
secondLayer.draw(in: CGRect(x: 0, y: 0, width: firstLayer.size.width, height: firstLayer.size.height) )
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
第一条路径:-
第二条路径:-
最终结果:-
终于有解决办法了!!
使用 https://github.com/adamwulf/ClippingBezier 你可以找到相交点。然后您可以沿着小路行走,顺时针左转,反之亦然,以留在外面。然后您可以使用点序列生成新路径。
您可以使用 GPCPolygon,它是 GPC
的 Objective-C 包装器-GPCPolygonSet*) initWithPolygons:(NSMutableArray*)points;
或
- (GPCPolygonSet*) unionWithPolygonSet:(GPCPolygonSet*)p2;
从 iOS 16 开始 CGPath 有 union(_:using:) 方法。
你可以从 UIBezierPath 中获取 CGPath,如果你再次需要 UIBezierPath,你可以使用 CGPath 来初始化它,如下所示:
let newPath: UIBezierPath = ///
let unionPath = existingPath.cgPath.union(newPath.cgPath)
existingPath = UIBezierPath(cgPath: unionPath)