1.はじめに
今回は計算用関数の投稿です。
指定した3点を通る円を描きたいと思い、挑戦しました。
今回は例として、一番左上から一番右下まで流れるような曲線を描きます。
※iPhoneXSとかのサンプル機の待ち受けで使われてるような線です。
2.全体のソースコード
circle.swift
import UIKit
class CirclePropaty{
var centerPoint :CGPoint = CGPoint(x: 0, y: 0)
var radius :CGFloat = 0
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let drawView = DrawView(frame: self.view.bounds)
self.view.addSubview(drawView)
// Do any additional setup after loading the view.
}
}
class DrawView: UIView {
override init(frame: CGRect) {
super.init(frame: frame);
self.backgroundColor = UIColor.clear;
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
//3点を通る円を計算する
var left_top : CGPoint = CGPoint(x: UIScreen.main.bounds.minX, y: UIScreen.main.bounds.minY)
var right_bottom : CGPoint = CGPoint(x: UIScreen.main.bounds.maxX, y: UIScreen.main.bounds.maxY)
var middle_point : CGPoint = CGPoint(x: UIScreen.main.bounds.width/3, y: UIScreen.main.bounds.height*2/3)
var circleData : CirclePropaty = calcCircle(pointA: left_top, pointB:right_bottom, pointC: middle_point)
var circle_center : CGPoint = circleData.centerPoint
var circle_radius : CGFloat = circleData.radius
// 円
let circle = UIBezierPath(arcCenter: circle_center, radius: circle_radius, startAngle: 0, endAngle: CGFloat(Double.pi)*2, clockwise: true)
// 内側の色
UIColor(red: 0, green: 1, blue: 0, alpha: 0.3).setFill()
// 内側を塗りつぶす
//circle.fill()
// 線の色
UIColor(red: 0, green: 1, blue: 0, alpha: 1.0).setStroke()
// 線の太さ
circle.lineWidth = 2.0
circle.stroke()
}
func calcCircle(pointA:CGPoint,pointB:CGPoint,pointC:CGPoint)->CirclePropaty{
let result = CirclePropaty()
//(原点-pointA)(原点-pointB)
var a : CGFloat = 0
var b : CGFloat = 0
var c : CGFloat = 0
a = 2 * pointB.x - 2 * pointA.x
b = 2 * pointB.y - 2 * pointA.y
c = pointA.x * pointA.x + pointA.y * pointA.y - pointB.x * pointB.x - pointB.y * pointB.y
//(原点-pointA)(原点-pointC)
var d : CGFloat = 0
var e : CGFloat = 0
var f : CGFloat = 0
d = 2 * pointC.x - 2 * pointA.x
e = 2 * pointC.y - 2 * pointA.y
f = pointA.x * pointA.x + pointA.y * pointA.y - pointC.x * pointC.x - pointC.y * pointC.y
result.centerPoint.x = (b * f - c * e)/(a * e - b * d)
result.centerPoint.y = (a * f - c * d)/(d * b - a * e)
result.radius = sqrt((pointA.x - result.centerPoint.x) * (pointA.x - result.centerPoint.x) + (pointA.y - result.centerPoint.y) * (pointA.y - result.centerPoint.y))
return result
}
}
3.解説
3-1.クラス定義
circle.swift
class CirclePropaty{
var centerPoint :CGPoint = CGPoint(x: 0, y: 0)
var radius :CGFloat = 0
}
関数の返却値として、半径と原点の位置を取得したいのでクラスを定義します。
3-2.計算関数
circle.swift
func calcCircle(pointA:CGPoint,pointB:CGPoint,pointC:CGPoint)->CirclePropaty{
let result = CirclePropaty()
//(原点-pointA)(原点-pointB)
var a : CGFloat = 0
var b : CGFloat = 0
var c : CGFloat = 0
a = 2 * pointB.x - 2 * pointA.x
b = 2 * pointB.y - 2 * pointA.y
c = pointA.x * pointA.x + pointA.y * pointA.y - pointB.x * pointB.x - pointB.y * pointB.y
//(原点-pointA)(原点-pointC)
var d : CGFloat = 0
var e : CGFloat = 0
var f : CGFloat = 0
d = 2 * pointC.x - 2 * pointA.x
e = 2 * pointC.y - 2 * pointA.y
f = pointA.x * pointA.x + pointA.y * pointA.y - pointC.x * pointC.x - pointC.y * pointC.y
result.centerPoint.x = (b * f - c * e)/(a * e - b * d)
result.centerPoint.y = (a * f - c * d)/(d * b - a * e)
result.radius = sqrt((pointA.x - result.centerPoint.x) * (pointA.x - result.centerPoint.x) + (pointA.y - result.centerPoint.y) * (pointA.y - result.centerPoint.y))
return result
}
3点を通る円はこの関数にCGPointを3つ渡してあげれば大丈夫です。
どうしてこうなるのかはググってみてください。
3-3.使用例
circle.swift
override func draw(_ rect: CGRect) {
var left_top : CGPoint = CGPoint(x: UIScreen.main.bounds.minX, y: UIScreen.main.bounds.minY)
var right_bottom : CGPoint = CGPoint(x: UIScreen.main.bounds.maxX, y: UIScreen.main.bounds.maxY)
var middle_point : CGPoint = CGPoint(x: UIScreen.main.bounds.width/3, y: UIScreen.main.bounds.height*2/3)
var circleData : CirclePropaty = calcCircle(pointA: left_top, pointB:right_bottom, pointC: middle_point)
var circle_center : CGPoint = circleData.centerPoint
var circle_radius : CGFloat = circleData.radius
// 円
let circle = UIBezierPath(arcCenter: circle_center, radius: circle_radius, startAngle: 0, endAngle: CGFloat(Double.pi)*2, clockwise: true)
// 内側の色
UIColor(red: 0, green: 1, blue: 0, alpha: 0.3).setFill()
// 線の色
UIColor(red: 0, green: 1, blue: 0, alpha: 1.0).setStroke()
// 線の太さ
circle.lineWidth = 2.0
circle.stroke()
}
自作クラスのUIViewのdrawにoverrideして、先ほど作成した関数を使って円を描いてみました。
このViewをViewControllerでaddSubviewしてあげればOKです。
4.終わりに
開発スピードを上げていきたいので説明を簡略化していこうかなと思い、今回から軽い説明に切り替えました。きっとみなさんならコードとにらめっこして理解してくれるはずと信じています。
以上。