ベジェ曲線って良く聞くんですが、イマイチ理解できてなかったので自前で描いてみました。
具体的にはベジェ曲線の座標を自分で計算して描画をしてみました。
ベジェ曲線の座標の求め方
ベジェ曲線の座標は制御点を使って求められます。
今回は下のように制御点が3つの場合のベジェ曲線を求めます。
まずはP1とP2、P2とP3の2点間をつなぎます。
次にP1-P2間で少しだけP1から離れた点P4とP2-P3で少しだけP2から離れたP5を決めて、それらをつなぎます。
そしてP4-P5間で少しだけP4から離れた点P6がベジェ曲線の座標になります。
段々とP4・P5をP2・P3に近づけて行きつつ、それぞれのP6を算出します。
ここで算出したP6を全てつなげればベジェ曲線になります。
今回はこれをSwiftで実装してみようと思います。
ベジェ曲線をSwiftで描画
今回はこの3つの制御点を使ったベジェ曲線を求めます。
現状のコードは下の通りです。
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let myView = MyView(frame: view.bounds) myView.backgroundColor = UIColor.white view.addSubview(myView) } } class MyView: UIView { let point1 = CGPoint(x: 100, y: 200) let point2 = CGPoint(x: 200, y: 100) let point3 = CGPoint(x: 300, y: 200) override func draw(_ rect: CGRect) { UIColor.darkGray.setFill() UIBezierPath(roundedRect: CGRect(origin: point1, size: CGSize(width: 5, height: 5)), cornerRadius: 2).fill() UIBezierPath(roundedRect: CGRect(origin: point2, size: CGSize(width: 5, height: 5)), cornerRadius: 2).fill() UIBezierPath(roundedRect: CGRect(origin: point3, size: CGSize(width: 5, height: 5)), cornerRadius: 2).fill() } }
先程描いたように、point1・point2・point3を元に、point6を求めてそれを繋いでいきます。
class MyView: UIView { let point1 = CGPoint(x: 100, y: 200) let point2 = CGPoint(x: 200, y: 100) let point3 = CGPoint(x: 300, y: 200) override func draw(_ rect: CGRect) { let count = 100 let path = UIBezierPath() path.move(to: point1) (0...count).forEach { let point4 = CGPoint( x: point1.x + (point2.x - point1.x) * CGFloat($0) / CGFloat(count), y: point1.y + (point2.y - point1.y) * CGFloat($0) / CGFloat(count) ) let point5 = CGPoint( x: point2.x + (point3.x - point2.x) * CGFloat($0) / CGFloat(count), y: point2.y + (point3.y - point2.y) * CGFloat($0) / CGFloat(count) ) let point6 = CGPoint( x: point4.x + (point5.x - point4.x) * CGFloat($0) / CGFloat(count), y: point4.y + (point5.y - point4.y) * CGFloat($0) / CGFloat(count) ) path.addLine(to: point6) } path.addLine(to: point3) path.lineWidth = 5.0 UIColor.brown.setStroke() path.stroke() } }
これを実行すると以下のようになります。
無事にきれいな曲線を引くことができました。