I need to calculate the intersection of two irregular UIBezierpaths say to closed paths representing irregular shapes. Problem is I don't even know how to get started on this. I've searched for libraries that could help but the only thing I found is a git repository missing files so it won't compile.
We can use Instance Methods on CGPath
-- either retrieved from UIBezierPath
or, a bit easier, working directly with CGMutablePath
.
See the Apple docs under Instance Methods here.
Depending on what you really want to do, though, you might not need to manipulate your path at all. You can use it as a mask ... you can use path contains(_ point: CGPoint)
... and so on.
But -- here is a really quick example of using CGPath
intersection(_:using:)
I'll make a few assumptions, such as you are adding an image view to a view subclass; tracking the touch began, moved, ended; using a CAShapeLayer
to "draw" the path outline; etc.
Looks kinda like this (tapping anywhere outside the gray frame will "clip" the path and fill it with green):
Simple UIView
subclass
class MyCanvasView: UIView {
let imgView = UIImageView()
private var myPath: CGMutablePath!
private var shapeLayer: CAShapeLayer = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
imgView.translatesAutoresizingMaskIntoConstraints = false
addSubview(imgView)
NSLayoutConstraint.activate([
imgView.topAnchor.constraint(equalTo: topAnchor, constant: 60.0),
imgView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 60.0),
imgView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -60.0),
imgView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -60.0),
])
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.systemRed.cgColor
shapeLayer.lineWidth = 2
self.layer.addSublayer(shapeLayer)
// in case there is no image set
imgView.backgroundColor = .systemYellow
self.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let t = touches.first else { return }
let pt = t.location(in: self)
myPath = CGMutablePath()
myPath.move(to: pt)
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.path = myPath
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let t = touches.first else { return }
let pt = t.location(in: self)
myPath.addLine(to: pt)
shapeLayer.path = myPath
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let t = touches.first else { return }
let pt = t.location(in: self)
myPath.closeSubpath()
shapeLayer.path = myPath
}
public func clipPath() {
let imgPath = CGMutablePath(rect: imgView.frame, transform: nil)
let clippedPath = imgPath.intersection(myPath)
shapeLayer.path = clippedPath
shapeLayer.fillColor = UIColor.green.cgColor
}
}
Test View Controller class
class TestPathsVC: UIViewController {
let canvasView = MyCanvasView()
override func viewDidLoad() {
super.viewDidLoad()
canvasView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(canvasView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
canvasView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
canvasView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
canvasView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
canvasView.heightAnchor.constraint(equalTo: canvasView.widthAnchor),
])
if let img = UIImage(named: "testPic") {
canvasView.imgView.image = img
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
canvasView.clipPath()
}
}