三点を通る円を求めるには、次のようにします。
ちょっと長いですが、やっていることは単純です。
#define eps 0.00001
// 0.0か?
#define EQ0(x) ((-eps <= (x)) && ((x) <= eps))
// 同一か?
#define EQ(a, b) (EQ0((a) - (b)))
// 直線の垂直二等分線算出
void CalcPerpLineSeg(double sx, double sy, double ex, double ey, double& a, double& b)
{
// 線の傾き
double a1 = (sy - ey) / (sx - ex);
// 垂直二等分線の傾き
if(EQ0(a1)){
a = 1.0;
}
else{
a = -1.0 / a1;
}
// 線の中点
double cx(sx + (ex - sx) / 2.0);
double cy(sy + (ey - sy) / 2.0);
// 求める切片
if(EQ0(a1)){
b = 0;
}
else{
b = cy - a * cx;
}
}
bool CircleBy3Point(double x1, double y1, double x2, double y2, double x3, double y3,
double& cx, double& cy, double& dRad)
{
// もし3点の中で同じ点が存在すれば、エラーとして返す
if( (EQ(x1, x2) && EQ(y1, y2))
|| (EQ(x2, x3) && EQ(y2, y3))
|| (EQ(x3, x1) && EQ(y3, y1))
){
return false;
}
// == 中心を算出 ==
// 与えられた二点の垂直二等分線を算出
double a, b, c, d;
CalcPerpLineSeg(x1, y1, x2, y2, a, b);
CalcPerpLineSeg(x2, y2, x3, y3, c, d);
// もし3点が直線上の点なら、円にはならない
if(EQ0(a - c)){
return false;
}
// 中心を算出
cx = (d - b) / (a - c);
cy = a * cx + b;
// 半径を算出
dRad = sqrt(pow(cx - x1, 2.0) + pow(cy - y1, 2.0));
return true;
}
※ 解説
この例では、三点を通る円を、次のようにして求めています。
まず、三点を通る、と言うことは、逆に言えばその三点は円周上にある、と言うことになります。
この三点を使い、直線を二本つくります。そして、その垂直二等分線をひいてみると、円の中心で交差することが分かります。
また、中心が求められれば、中心と三点のうちのいずれかの点との距離を求めることにより、半径を求められます。
二点間の距離はこちらをご参照ください。
この方法の条件としては、三点がいずれも違う点であること、三点が同一直線上に並んでいないこと、です。
同一直線上にある三点からは、円は定義できません。
(C) 2002 atelier-peppe
ababa@atelier-peppe.sakura.ne.jp
|