平面上の3点を通る円の中心座標と半径の求め方。三角形の外接円を求めたりできる。
// Run Over: Detail
// 3点を通る円の中心点と半径を求める
//
// 行列式
float det(vector a; vector b; vector c;)
{
return a.x*b.y*c.z + a.z*b.x*c.y + a.y*b.z*c.x - a.z*b.y*c.x - a.y*b.x*c.z - a.x*b.z*c.y;
}
// input0に入力された3点を使う
vector p0 = point(0, "P", 0);
vector p1 = point(0, "P", 1);
vector p2 = point(0, "P", 2);
vector a = set(p0.x, p1.x, p2.x);
vector b = set(p0.z, p1.z, p2.z);
vector c = set(1, 1, 1);
vector d = set(-(p0.x * p0.x) - (p0.z * p0.z), -(p1.x * p1.x) - (p1.z * p1.z), -(p2.x * p2.x) - (p2.z * p2.z));
float l = det(d, b, c) / det(a, b, c);
float m = det(a, d, c) / det(a, b, c);
float n = det(a, b, d) / det(a, b, c);
// 中心点
addpoint(0, set(-l/2, 0, -m/2));
// 中心座標と半径
v@center = set(-l/2, 0, -m/2);
f@radius = sqrt((l*l + m*m - 4*n) / 4);
コードの解説
原点を通る半径4の円の式は
x^2 + y^2 = 16
点(-5, 3)を通る半径4の円の式は
(x + 5)^2 + (y – 3)^2 = 16
となる。これを展開すると
x^2 + y^2 + 10x + 6y + 18 = 0
つまり求める円の方程式は x^2 + y^2 + lx + my + n = 0 という形になる。
l, m, nを求める
これを一次関数 ax + by + cz = d の形にすると
lx + my + n = -x^2 – y^2
3頂点の座標をx,yに入力して3つの一次関数の式をつくりクラメル式で解く。
3頂点をそれぞれp0, p1, p2とすると
p0.x * l + p0.z * m + 1 * n = -p0.x ^ 2 – p0.z ^ 2
p1.x * l + p1.z * m + 1 * n = -p1.x ^ 2 – p1.z ^ 2
p2.x * l + p2.z * m + 1 * n = -p2.x ^ 2 – p2.z ^ 2
となるので、
a = (p0.x, p1.x, p2.x)
b = (p0.z, p1.z, p2.z)
c = (1, 1, 1)
d = (-p0.x ^ 2 – p0.z ^ 2, -p1.x ^ 2 – p1.z ^ 2, -p2.x ^ 2 – p2.z ^ 2)
行列式でそれぞれを求める
l = det(d, b, c) / det(a, b, c)
m = det(a, d, c) / det(a, b, c)
n = det(a, b, d) / det(a, b, c)
中心座標と半径の式
x^2 + y^2 + lx + my + n = 0 を円の方程式 (x-a)^2 + (y-b)^2 = r^2 の形にする。
x^2 + y^2 + lx + my + n = 0 を平方完成すると (x + l/2)^2 + (y + m/2)^2 = (l^2 + m^2 – 4n)/4 となるので、中心座標は (-l/2, -m/2) になり、半径はsqrt((l^2 + m^2 – 4n)/4) となる。
先ほどのl、m、nの値を代入すれば求まる。