[Swift5]3点を通る円を計算する

#1.はじめに
今回は計算用関数の投稿です。
指定した3点を通る円を描きたいと思い、挑戦しました。
今回は例として、一番左上から一番右下まで流れるような曲線を描きます。
※iPhoneXSとかのサンプル機の待ち受けで使われてるような線です。

#2.全体のソースコード
```Swift: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.クラス定義

```Swift:circle.swift
class CirclePropaty{
    var centerPoint :CGPoint = CGPoint(x: 0, y: 0)
    var radius :CGFloat = 0
}
```
関数の返却値として、半径と原点の位置を取得したいのでクラスを定義します。

##3-2.計算関数

```Swift: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.使用例
```Swift: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.終わりに
開発スピードを上げていきたいので説明を簡略化していこうかなと思い、今回から軽い説明に切り替えました。きっとみなさんならコードとにらめっこして理解してくれるはずと信じています。

以上。