web-dev-qa-db-ja.com

楕円が円と交差する(衝突する)かどうかを検出する方法

衝突システムを改善したい。

現在、2つの不規則なオブジェクトが、それらの境界の長方形が衝突した場合に衝突するかどうかを検出します。

長方形の場合は対応する楕円を取得し、もう一方の長方形は円を使用するようにします。楕円座標を取得する方法を見つけましたが、それが円と交差するかどうかを検出しようとすると問題が発生します。

円が楕円と交差するかどうかをテストするアルゴリズムを知っていますか?

21
adiian

簡単な答え:2つのオブジェクトが交差するかどうかを正確に解決することは、衝突検出の目的では実行不可能なほど複雑です。楕円をいくつかのnのn辺のポリゴンとして離散化し(必要な精度に応じて)、そのポリゴンとの衝突検出を行います。

長い答え:滑らかな楕円と円が交差するかどうかを判断することを主張する場合、2つの主要なアプローチがあります。どちらも、最初に楕円上の円の中心に最も近い点を解き、次にその距離を円の半径と比較する必要があります。

アプローチ1:楕円のパラメーター化を使用します。楕円が原点にあり、その軸がx-y軸に位置合わせされるように、座標を変換します。あれは:

  • 楕円の中心:(0,0)
  • 円の中心:c =(cx、cy)
  • 円の半径:r
  • 楕円のx整列軸の半径:a
  • 楕円のy整列軸の半径:b。

楕円の方程式は、a cos(t), b sin(t)で与えられます。最も近い点を見つけるために、二乗距離|| (a cos t, b sin t) - c ||^2を最小化します。 Jeanが指摘するように、これは「微積分」です。導関数を取り、それを0に設定します。ただし、何かが足りない場合を除いて、結果の(かなり厄介な)方程式をtで解くことはできません。分析的に、そして例えばを使用して概算する必要がありますニュートン法。見つけたtをパラメトリック方程式に接続して、最も近い点を取得します。

  • 長所:数値解法は、tという1つの変数にのみ含まれます。
  • 短所:楕円のパラメータ化を書き留めるか、できるように座標を変換できる必要があります。これは、楕円を合理的に表現するのにそれほど難しいことではありません。ただし、2番目の方法を紹介します。これは、はるかに一般的で、問題を3Dなどに一般化する必要がある場合に役立つ可能性があります。

アプローチ2:多次元微積分を使用します。座標を変更する必要はありません。

  • 円の中心:c =(cx、cy)
  • 円周の半径:r
  • 楕円は、関数gに対してg(x、y)= 0で与えられます。たとえば、カードの回答によれば、g(x、y)=焦点1からの(x、y)の距離+焦点2-eからの(x、y)の距離を使用できます。

円の中心に最も近い楕円上の点を見つけることは、制約付き最小化問題として表現できます。

Minimize ||(x,y) - c||^2 subject to g(x,y) = 0

(2乗距離を最小化することは、距離を最小化することと同等であり、x、yの2次多項式であるため、処理がはるかに快適です。)

制約付き最小化問題を解くために、ラグランジュ乗数ラムダを導入し、連立方程式を解きます。

2 * [ (x,y) -c ] + lambda * Jg(x,y) = 0
g(x,y) = 0

ここで、Jgはgの勾配です。これは、x、y、ラムダの3つの未知数の3つの(非線形)方程式のシステムです。ニュートン法を使用してこのシステムを解くことができ、得られる(x、y)は円の中心に最も近い点です。

  • 長所:パラメータ化を見つける必要はありません
  • 長所:方法は非常に一般的であり、パラメトリック方程式を見つけるよりもgを書く方が簡単な場合はいつでもうまく機能します(3Dなど)
  • 短所:多変数ニュートン解法が必要です。これは、数値解法パッケージにアクセスできない場合は非常に厄介です。

警告:これらのアプローチは両方とも、円の中心までの距離を極限する点を技術的に解決します。したがって、見つかったポイントは、円から最も遠いポイントであり、最も近いポイントではない可能性があります。どちらの方法でも、適切な初期推測を使用してソルブをシードすると(円の中心は方法2で適切に機能し、方法1では自分で作業します)、この危険性が軽減されます。

潜在的な3番目のアプローチ?:円と楕円を表す2つの変数で、2つの2次方程式のシステムの根を直接解くことができる場合があります。実際のルートが存在する場合、オブジェクトは交差します。このシステムを解く最も直接的な方法は、ニュートン法のような数値アルゴリズムを使用しても役に立ちません。収束がないからといって、実根が存在しないことを意味する必要はないからです。ただし、2つの変数の2つの二次方程式の場合、実根が存在する場合はそれを見つけることが保証されている特殊な方法が存在する可能性があります。私自身はこれを行う方法を考えることはできませんが、自分で調査することをお勧めします(または、stackoverflowの誰かが詳しく説明できるかどうかを確認してください)。

23
user168715

楕円は、点Aまでの距離と点Bまでの距離の合計が一定である点のセットとして定義されます。 (AとBは楕円の焦点と呼ばれます)。

AP + BPの合計がe未満であるすべてのポイントPは、楕円の中にあります。

円は、点Cまでの距離がrである点のセットとして定義されます。

円と楕円の交差の簡単なテストは次のとおりです。

検索
円と線ACの交点としてのPと
Qは円と線BCの交点です。

円と楕円が交差する(または円が完全に楕円の中にある)場合
AP + BP <= eまたはAQ + BQ <= e

alt text

[〜#〜]編集[〜#〜]

Martin DeMelloのコメントとそれに応じて私の答えを適応させた後、私は問題についてもっと考え、答え(2番目のチェックを含む)がまだall交差点を検出しないことを発見しました:

円と楕円がほとんど交差していない場合(接線より少し多い場合)、PとQは楕円内にありません。

alt text

したがって、上記のテストでは、重なりが「十分に大きい」場合にのみ衝突が検出されます。数学的には完璧ではありませんが、実用的な目的には十分かもしれません。

19
Curd

手遅れであることは知っていますが、誰かの助けになることを願っています。この問題を解決するための私のアプローチは、楕円をn次元のポリゴンに補間し、2点ごとに線を作成して、円がいずれかの線と交差するかどうかを確認することでした。これは最高のパフォーマンスを提供しませんが、便利で実装が簡単です。

楕円をn次元のポリゴンに補間するには、次を使用できます。

float delta = (2 * PI) / n;

std::vector<Point*> interpolation;

for(float t = 0; t < (2 * PI); t += delta) {

    float x = rx * cos(t) + c->get_x();
    float y = ry * sin(t) + c->get_y();

    interpolation.Push_back(new Point(x, y));
}

c:楕円の中心。 rx:楕円のx整列軸の半径。 ry:楕円のy方向に整列した軸の半径。

これで補間点ができたので、2点ごとに円と線の交点を見つけることができます。線と円の交点を見つける1つの方法を説明します ここ 、交点は、線と円のいずれかとの交点が発生した場合に発生します。

これが誰かに役立つことを願っています。

5
Moe

楕円の主半径と副半径を円の半径だけ拡大します。次に、拡大された楕円の焦点までの距離を合計して、指定された円の中心がこの新しい大きな楕円内にあるかどうかをテストします。

このアルゴリズムは非常に効率的です。指定された円が楕円に外接する円と交差しない場合は、早期に終了できます。これはバウンディングボックステストよりも低速ですが、軸に位置合わせされていない楕円のバウンディングボックスを見つけるのは難しいです。

3
Danny Epstein

円と楕円が衝突する場合、それらの境界は1、2、3、または4回交差するか(または円と一致する円形楕円の場合は無限に多く)、または円が楕円内にあるか、またはその逆です。 。

円の方程式は(x --a)^ 2 +(y --b)^ 2 <= r ^ 2(1)であり、楕円の方程式は[(x --c)^ 2] /であると仮定します。 [d ^ 2] + [(y --e)^ 2]/[f ^ 2] <= 1(2)

それらの一方が他方の内側にあるかどうかを確認するには、楕円の中心の座標(x = c、y = e)で円の方程式を評価するか、またはその逆を行い、不等式が成り立つかどうかを確認します。

それらの境界が交差する他のケースをチェックするには、(1)と(2)で記述された連立方程式に解があるかどうかをチェックする必要があります。

これを行うには、(1)と(2)を追加して、

_(x - a)^2 + (y - b)^2 + [(x - c)^2]/[d^2] + [(y - e)^2]/[f^2] = r^2 + 1_

次に、用語を掛けて、

_x^2 - 2ax + a^2 + y^2 - 2by + b^2 + x^2/d^2 - 2cx/d^2 + c^2/d^2 + y^2/f^2 - 2ey/f^2 + e^2/f^2 = r^2 + 1_

同類項を収集すると、

_(1 + 1/d^2)x^2 - (2a + 2c/d^2)x + (1 + 1/f^2)y^2 - (2b + 2e/f^2)y = 1 + r^2 - a^2 - b^2 - c^2/d^2 - e^2/f^2_

m = (1 + 1/d^2), n = -(2a + 2c/d^2), o = (1 + 1/f^2), and p = -(2b + 2e/f^2)をしましょう

方程式は_mx^2 + nx + oy^2 + py = 1 + r^2 - a^2 - b^2 - c^2/d^2 - e^2/f^2_になりました

次に、左側の正方形を完成させる必要があります

_m[x^2 + (n/m)x] + o[y^2 + (p/o)y] = 1 + r^2 - a^2 - b^2 - c^2/d^2 - e^2/f^2

m[x^2 + (n/m)x + (n/2m)^2 - (n/2m)^2] + o[y^2 + (p/o)y + (p/2o)^2 - (p/2o)^2] = 1 + r^2 - a^2 - b^2 - c^2/d^2 - e^2/f^2

m[(x + n/2m)^2 - (n/2m)^2] + o[(y + p/2o)^2 - (p/2o)^2] = 1 + r^2 - a^2 - b^2 - c^2/d^2 - e^2/f^2

m(x + n/2m)^2 - m(n/2m)^2 + o(y + p/2o)^2 - o(p/2o)^2 = 1 + r^2 - a^2 - b^2 - c^2/d^2 - e^2/f^2

m(x + n/2m)^2 + o(y + p/2o)^2 = 1 + r^2 - a^2 - b^2 - c^2/d^2 - e^2/f^2 + m(n/2m)^2 + o(p/2o)^2
_

このシステムには解決策がありますiff 11 + r^2 - a^2 - b^2 - c^2/d^2 - e^2/f^2 + m(n/2m)^2 + o(p/2o)^2 >= 0

私が代数的な間違いをしなかったなら、あなたはそれを持っています。結果の式をどれだけ単純化できるかわかりません。そのため、多くの円/楕円をチェックする場合、このソリューションは計算コストが非常に高くなる可能性があります。

3
Bwmat

円の中心に最も近い楕円上の点を見つけます
次に、この点からの距離が円の半径よりも小さいかどうかを確認します
これを行うのに助けが必要な場合はコメントするだけですが、それは単なる微積分です

編集:カードに何か問題があるので、これが解決に向けた方法です

楕円上の与えられた中心αβ
そして(用語を覚えていないため)x半径a、y半径bパラメータ化は
r(Θ)=(ab)/(((BcosΘ)^ 2 +(asinΘ)^ 2)^。5)
x(Θ)=α+ sin(Θ)r(Θ)
y(Θ)=β+ cos(Θ)r(Θ)

次に、中心が(φ、ψ)で半径がrの円を取り、距離d(Θ)=((φ--x(Θ))^ 2 +(ψ--y(Θ))^ 2)^を取ります。 5

この距離の最小値は、d '(Θ)= 0(導関数の場合は')の場合です。

d '(Θ)= 1/d(Θ)*(-φx'(Θ)+ x(Θ)x '(Θ)-ψy'(Θ)+ y(Θ)y '(Θ))
==>
x '(Θ)*(-φ+ x(Θ))= y'(Θ)*(ψ--y(Θ))

続けて行き、うまくいけばΘを解くことができます
作業しているフレームワークには、これを解決するのに役立つものがある可能性があり、 ニュートン法 を介していつでも簡単な方法で根を近似することができます。

数学的な解決策を忘れてください。描画で簡単にわかるように、最大​​4つの解、つまり4年生の多項式を使用できます。

代わりに、図の1つのエッジに沿ってバイナリ検索を実行します。ポイントが楕円内にあるかどうか、さらには円内にあるかどうかを簡単に判断できます(距離が半径よりも短いかどうかを確認してください)。

あなたが本当に数学に行きたいのなら、Wolfram MathWorldはここに素晴らしい記事を持っています: http://mathworld.wolfram.com/Circle-EllipseIntersection.html しかし、警告されます、あなたはまだしなければならないでしょうおそらく二分探索のようなものを使用して、多項式方程式ソルバーを記述します。

3
Thomas Ahle

2つの楕円間の接触に関するより一般的な問題についていくつかの情報を提供したいと思いました。 2つの楕円の最接近距離の計算は長年の問題であり、過去10年以内に分析的にのみ解決されました。これは決して単純なことではありません。この問題の解決策はここにあります http://www.e-lc.org/docs/2007_01_17_00_46_52/

2つの楕円の間に接触があるかどうかを判断する一般的な方法は、最初に現在の構成で楕円が最も接近する距離を計算し、次にこれを現在の分離の大きさから差し引くことです。この結果が0以下の場合、それらは接触しています。

誰かが興味を持っているなら、私は最も近いアプローチの距離を計算するコードを投稿することができます-それはC++です。コードは2つの任意の楕円の一般的なケース用ですが、円は短軸と長軸が等しい楕円であるため、円と楕円に対しても明らかに実行できます。

1
Fred Minkowski

仮定:楕円は原点を中心とし、(長さaの)半長軸がx軸に沿って方向付けられ、長さbの半短軸があります。 E2は、離心率の2乗、つまり(a a-b b)/(a * a);です。円はX、Yを中心とし、半径rです。

簡単なケースは次のとおりです。円の中心が楕円の内側にあるため(つまり、hypot(X/a、Y/b)<= 1)、交差があります。円の中心は、半径a + rの0を中心とする円の外側にあるため(つまり、hypot(X、Y)> a + r)、交差はありません。

他の場合の1つのアプローチは、円の中心の測地座標(緯度、高さ)を計算することです。高さが半径よりも小さい場合に限り、円は楕円と交差します。

楕円上の点の地理的緯度は、その点での楕円の法線がx軸となす角度であり、楕円の外側の点の高さは、それに最も近い楕円上の点からの点の距離です。 。測地緯度は、楕円が実際に円形でない限り、楕円の中心から点までの極角と同じではないことに注意してください。

式では、測地座標lat、htからデカルト座標X、Yへの変換はX =(nu + ht)* cos(lat)、Y =(nu *(1-E2)+ ht)* sin(lat)ここで、nu = a/sqrt(1-E2 * sin(lat)sin(lat))。X、Yに最も近い楕円上の点は、同じ緯度で高さがゼロの点です。つまり、x = n cos(lat)、y = nu *(1-E2)* sin(lat)。 nuは緯度の関数であることに注意してください。

残念ながら、X、Yからlat、htを見つけるプロセスは、反復的なものです。 1つのアプローチは、最初に緯度を見つけ、次に高さを見つけることです。

小さな代数は、緯度がlat = atan2(Y + E2 * nu sin(lat)、X)を満たすことを示しています。これは、lat = atan2(Y、Xから始まる緯度の連続近似を計算するために使用できます。 =(1.0-E2))、または(より効率的に)ニュートン法を使用して解くことができます。

E2が大きいほど、つまり楕円が平らであるほど、より多くの反復が必要になります。たとえば、楕円がほぼ円形(たとえば、E2 <0.1)の場合、5回の反復でx、yがa * 1e-12以内になりますが、楕円が非常に平坦な場合、たとえば、 E2 = 0.999同じ精度を得るには、約300回の反復が必要です。

最後に、緯度が与えられると、高さは(x、y)を計算することによって計算できます:x = nu cos(lat)、y = n(1-E2)* sin(lat)そしてhはx、yから円の中心までの距離です。h= hypot(Xx、Yy)

1
dmuir

これはそれほど難しいことではありません。 user168715の答えは一般的に正しいですが、微積分を行う必要はありません。三角法だけです。

2つのオブジェクトの中心間の角度を見つけます。これを使用すると、極形式を使用して、楕円上の円の中心に最も近い点を見つけることができます。

Ellipse Equation : Polar form relative to center

(ウィキペディアの記事から引用 省略記号

次に、楕円の半径と円の半径を差し引いて、2つのオブジェクトの中心間の距離を比較します。

多分私は何かが足りない。 ArcTan/Cos/Sinは遅いかもしれませんが、私はそうは思いません。必要に応じて、速い近似が必要です。

1
phillipwei