円と円の交点
目次
# 解説
2つの円の中心座標C1, C2と半径R1, R2が与えられて、その交点の座標を求めるアルゴリズム.
例えば以下のような条件.
ここでは関係ないが、交点を持つかどうかは中心間の距離が半径の合計より大きいかどうかを見れば良い.
交点と中心を三角形とみなすと、三辺の長さが分かっている.
よって余弦定理で中心間の線分ベクトルと交点へのベクトルの角度が求められる.
また、長さは円の半径である.
回転行列によりベクトルを回転させ、半径の長さでベクトルを伸縮してやれば交点になる.
交点は2つあるので、もう一つのベクトルは逆回転行列で逆回転させる.
# コード
pair<Vector2, Vector2> crossPoints() {
Vector2 baseVec = C2 - C1;
double baseLen = baseVec.length();
double cos_ = (baseLen*baseLen + R1*R1 - R2*R2) / (2 * baseLen * R1);
double sin_ = sqrt(1 - cos_*cos_);
// Counter-clockwise
Vector2 a_(cos_ * baseVec.x + -sin_ * baseVec.y, sin_ * baseVec.x + cos_ * baseVec.y);
// Clockwise
Vector2 b_(cos_ * baseVec.x + sin_ * baseVec.y, -sin_ * baseVec.x + cos_ * baseVec.y);
Vector2 a = C1 + a_ * R1 / baseLen;
Vector2 b = C1 + b_ * R1 / baseLen;
if (fabs(a.x) < EPS) a.x = 0.0;
if (fabs(a.y) < EPS) a.y = 0.0;
if (fabs(b.x) < EPS) b.x = 0.0;
if (fabs(b.y) < EPS) b.y = 0.0;
if (a < b) return make_pair(a, b);
return make_pair(b, a);
}
# ボツになったアルゴリズム
2つの交点を通る直線への垂線までの長さは半径の長さに比例するという仮定に基づいたアルゴリズム.
- 2円の半径の比から直線と線分の交点を求める.
- 線分に垂直でかつを始点とする単位ベクトルを求める.
- 三平方の定理でから2交点, への距離を求める.
- 交点を計算する.
以下の入力でうまく動かない.
後ほど調査する.
0 0 10
0 10 8
Vector2 mid(Vector2 c1, double r1, Vector2 c2, double r2) {
return c1 + (c2 - c1) * (r1 / (r1 + r2));
}
Vector2 perpen(Vector2 a, Vector2 b) {
Vector2 c = b - a;
double d = c.x;
c.x = c.y;
c.y = -d;
return c;
}
Vector2 unitVec(Vector2 v) {
return v / v.length();
}
pair<Vector2, Vector2> crossPoints() {
Vector2 p = mid(C1, R1, C2, R2);
cout << p << endl;
Vector2 e = unitVec(perpen(C1, p));
double len = sqrt(R1*R1 - (p - C1).norm());
Vector2 x1 = p + e * len;
Vector2 x2 = p + e * (-len);
if (fabs(x1.x) < EPS) x1.x = 0.0;
if (fabs(x1.y) < EPS) x1.y = 0.0;
if (fabs(x2.x) < EPS) x2.x = 0.0;
if (fabs(x2.y) < EPS) x2.y = 0.0;
if (x1 < x2) return make_pair(x1, x2);
return make_pair(x2, x1);
}