イナヅマTVログ

【Canvas練習ノート】線(Line)と円(Circle)の当たり判定

| 2件のコメント

線と円の当たりというか衝突というか交差したかどうかを判定してたい。

ActionScript だと hitTest が使えたのでコツコツと自力で判定コードを書くのは始めてかも。
色々良くわかってないので、なんだかとっても大変だった。

demo
line_circle_intercect

Web上にはたくさんの知恵があります。

MathWorld: Circle-Line Intersection
stackoverflow: Circle line collision detection
MATHEMATICS: How do I calculate the intersection(s) of a straight line and a circle?
Circle-Line Intersection

そのものズバリなのにコードをどう書いていいか見当が付かない。
いや、コードの例示もあるけど意味が分からないから書けない。

なんかアルゴリズムはある風なのに…

ボンクラ脳なので一つずつ順番に考えることにしました。

  1. 線の両端が円の外側だと何もしない
  2. 線の両端は円の外側ではないらしい -> 下図の三角形の高さ(h)が円の半径以下だと当たり
    line_circle_triangle
    ここからは算数が良くわからない自分のためのメモです。

ACが線(Line)です。
Bは円の中心です。
AB, BC, CAの各辺の長さは分かります。
三角形の各辺の長さが分かっている場合の高さ(h)は「ヘロンの公式」で求められるらしい。

h * h = ( (a+b+c)*(a-b+c)*(-a+b+c)*(a+b-c) )/(4*a*a)

BD = Math.sqrt( ( ( AC+BC+AB )*( AC-BC+AB )*( -AC+BC+AB )*( AC+BC-AB ) ) / ( 4*AC*AC ) );

三平方の定理とヘロン三角形の話
こちらに大変詳しく解説されています、ありがとうございます。
ちんぷんかんぷんだけど…

demo
line_circle_intercect

やりたかったことはできたっぽいけど、もっと良い方法がありそうな気がします。
判定も総当たりしてるので効率化余地大なので何とかしたい。
矩形と線の当たり判定もしたいなー。

いや〜、hitTest って大変なんや〜。
物理エンジンとか作ってる人スゲー!
と暑い暑い日にしみじみと思いました。

2件のコメント

  1. B-Dは円の中心から線分への垂線ですね。
    ですから、A-Dの長さをA-Cの単位ベクトルとA-Bのベクトルの内積で求め、
    三角関数でB-Dを求めるのはどうでしょう。
    ヘロンの公式に、座標から長さを求める分を組み込むより、ベクトルクラス
    を設けて、随所でベクトル演算するようにした方が最後は楽になりそうです。
    C#だとこんな感じ
    public class Vect
    {
    public double X;
    public double Y;
    public Vect(double x, double y) { X = x; Y = y; }
    public static override Vect operator /(Vect v, double l) { return new Vect(v.X / l, v.Y / l); }
    public double Len() { return Math.Sqrt(X*X + Y*Y); }
    public Vect 単位ベクトル() { return this / this.Len(); }
    public double 内積値(Vect v) { return (X * v.X + Y * v.Y); }
    }

    bool IsHit
    {
    Vect ab = new Vect(Bx-Ax, By-Ay);
    Vect ac = new Vect(Cx-Ax, Cy-Ay)
    double lenAD = ab.内積値(ac.単位ベクトル);
    double lenAB = ab.Len();
    double lenBD = Math.Sqrt(lenAD*lenAD + lenAB * lenAB);
    return 円の半径 >= lenBD;
    }

  2. ありがとうございます。
    なにかの呪文にしか見えないのが悲しいです…
    参考にさせていただきます!!

コメントを残す