3点を通る円を求める

## 3点を通る円の中心と半径を求める
点 $A(x_1,y_1)$、点 $B(x_2,y_2)$、点 $C(x_3,y_3)$ を通る円の中心 $P$ と半径 $r$ を求める。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384860/30817f13-629b-60e2-c4f6-3dbda8dc15dd.png">

## 求め方
3点を通る円の中心は、その三点を頂点とする三角形の外心となる。
（求める円はその三点を頂点とする三角形の外接円）
三角形の各辺の垂直二等分線の交点がその三角形の外心となる。
外心は3つの頂点から等距離にある。
その外心から各点の頂点の距離が円の半径となる。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384860/eb2ede89-d1a0-592a-f64f-3128a6735dbd.png">

## 外心の求め方

1. 点 $A$ と点 $B$ の中点 $D$ を求める
2. 点 $A$ と点 $B$ を通る直線に垂直な 点 $D$ を通る直線 $L_1$ を求める
3. 点 $A$ と点 $C$ の中点 $E$ を求める
4. 点 $A$ と点 $C$ を通る直線に垂直な 点 $E$ を通る直線 $L_2$ を求める
5. 直線 $L_1$ と直線 $L_2$ の交点を求める

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384860/28726a11-898f-6e53-d5d5-d4df86677ce9.png">

## 求める
点 $A$ と点 $B$ の中点 $D$ は、
$$D=\left(\frac{x_1+x_2}{2},\frac{y_1+y_2}{2}\right)$$
点 $A$ と点 $B$ を通る直線の方程式は、（[直線の方程式](https://qiita.com/tydesign/items/4d3909a826363d8fc29f) 参照）
$$(y_2-y_1)x+(x_1-x_2)y+(x_2y_1-x_1y_2)=0$$
この直線の法線ベクトルは、$\\{(y_2-y_1),(x_1-x_2)\\}$ なので、
点 $A$ と点 $B$ を通る直線に垂直な直線の傾きは、 $\dfrac{x_1-x_2}{y_2-y_1}$
よって、直線 $L_1$ の方程式は、1点と傾きが与えられた[直線の方程式](https://qiita.com/tydesign/items/4d3909a826363d8fc29f)の公式により、
$$y-\frac{y_1+y_2}{2}=\frac{x_1-x_2}{y_2-y_1}\left(x-\frac{x_1+x_2}{2}\right)$$
右辺を展開して、
$$y-\frac{y_1+y_2}{2}=\frac{x(x_1-x_2)}{y_2-y_1}-\frac{(x_1+x_2)(x_1-x_2)}{2(y_2-y_1)}$$
$$y-\frac{y_1+y_2}{2}=\frac{2x(x_1-x_2)-(x_1+x_2)(x_1-x_2)}{2(y_2-y_1)}$$
両辺に $2(y_2-y_1)$ を掛けて、
$$2y(y_2-y_1)-(y_1+y_2)(y_2-y_1)=2x(x_1-x_2)-(x_1+x_2)(x_1-x_2)$$
片方の辺に集めて、
$$2x(x_1-x_2)+2y(y_1+y_2)+\\{(x_2+x_1)(x_2-x_1)+(y_2+y_1)(y_2-y_1)\\}=0$$
よって、
$$L_1 : (x_1-x_2)x+(y_1-y_2)y+\frac{x_2^2-x_1^2+y_2^2-y_1^2}{2}=0\ \cdots \ ①$$
同じ要領で、点 $A$ と点 $C$ を通る直線に垂直な 中点 $E$ を通る直線 $L_2$ を求めると、
$$L_2 : (x_1-x_3)x+(y_1-y_3)y+\frac{x_3^2-x_1^2+y_3^2-y_1^2}{2}=0\ \cdots \ ②$$
[2直線の交点を求める](https://qiita.com/tydesign/items/feda4c0dd48ea269bb14) 公式を使って、$L_1$ と $L_2$ の交点を求める。
交点を $P$ とし、その座標を $(x_p,y_p)$ とすると、
$$x_p=\frac{(y_1-y_2)(x_3^2-x_1^2+y_3^2-y_1^2)-(y_1-y_3)(x_2^2-x_1^2+y_2^2-y_1^2)}{2(x_1-x_2)(y_1-y_3)-2(x_1-x_3)(y_1-y_2)}$$
$$y_p=\frac{(x_1-x_3)(x_2^2-x_1^2+y_2^2-y_1^2)-(x_1-x_2)(x_3^2-x_1^2+y_3^2-y_1^2)}{2(x_1-x_2)(y_1-y_3)-2(x_1-x_3)(y_1-y_2)}$$
となる。

また、半径 $r$ は、点 $A$ から点 $P$ までの距離を、2点間の距離の公式を使って求めると、
$$ r = \sqrt{(x_p - x_1)^2 + (y_p - y_1)^2}$$
となる。

## 3点を指示して円を作成するプログラム
```scheme
;; 3点を指示して円を作成
(defun c:ThreePointCircle (/ p1 p2 p3 c)
    (setq p1 (getpoint "\n1点目を指示")
          p2 (getpoint "\n2点目を指示")
          p3 (getpoint "\n3点目を指示")
          c (circle:3Points p1 p2 p3)
    )
    (entmake:Circle (car c) (cadr c))
    (princ)
) 

;; == sub functions ==
;; 3点を通る円の中心と半径を求める
(defun circle:3Points (p1 p2 p3
	/ x1 x2 x3 y1 y2 y3 x1-x2 x1-x3y1-y2 y1-y3 a b c c1 c2 xp yp)
    (setq x1 (car  p1)
          y1 (cadr p1)
          x2 (car  p2)
          y2 (cadr p2)
          x3 (car  p3)
          y3 (cadr p3)
    )

    (setq x1-x2 (- x1 x2)
          x1-x3 (- x1 x3)
          y1-y2 (- y1 y2)
          y1-y3 (- y1 y3)
          c1 (- (+ (- (* x2 x2)(* x1 x1))(* y2 y2))(* y1 y1))
          c2 (- (+ (- (* x3 x3)(* x1 x1))(* y3 y3))(* y1 y1))
          a (- (* 2 x1-x2 y1-y3)(* 2 x1-x3 y1-y2))
          b (- (* y1-y2 c2) (* y1-y3 c1))
          c (- (* x1-x3 c1) (* x1-x2 c2))
    )
    (setq xp (/ b a)
          yp (/ c a))
    (list (list xp yp) (sqrt (+ (* (- xp x1) (- xp x1))(* (- yp y1) (- yp y1)))))
)
;; 中心と半径を指定して円を作成
(defun entmake:CircleBase (c r) (list '(000 . "CIRCLE") (cons 10 c) (cons 40 r)))
(defun entmake:Circle (c r) (entmake (entmake:CircleBase c r)) (entlast))
```

## 3点を指示して円を作成するプログラム（AutoLISP関数使用）
```scheme
;; 3点を指示して円を作成
(defun c:ThreePointCircle2 (/ p1 p2 p3)
    (setq p1 (getpoint "\n1点目を指示")
          p2 (getpoint "\n2点目を指示")
          p3 (getpoint "\n3点目を指示")
    )
    (entmake:CircleFrom3Points p1 p2 p3)
    (princ)
)

;; == sub functions ==
;; 円周上の3点から円の中心を求める（AutoLISP関数使用）
(defun circle:GetCenterPointFrom3Points (p1 p2 p3 / ma mb va vb)
    (if (setq ma (mapcar '(lambda (a b) (/ (+ a b) 2.)) p1 p2)
              va (mapcar '- p2 p1) 
              mb (mapcar '(lambda (a b) (/ (+ a b) 2.)) p2 p3)
              vb (mapcar '- p3 p2) 
        )
        (inters ma (mapcar '+ ma (list (- (cadr va)) (car va) 0))
                mb (mapcar '+ mb (list (- (cadr vb)) (car vb) 0))
                nil
        )
    )
)
;; 中心と半径を指定して円を作成
(defun entmake:CircleBase (c r) (list '(000 . "CIRCLE") (cons 10 c) (cons 40 r)))
(defun entmake:Circle (c r) (entmake (entmake:CircleBase c r)) (entlast))
;; 3点を指定して円を作成
(defun entmake:CircleFrom3Points (p1 p2 p3 / cp)
    (entmake:Circle
        (setq cp (circle:GetCenterPointFrom3Points p1 p2 p3))
        (distance cp p1)
    )
)
```