X1、Y1、Z1-X2、Y2、Z2およびX3、Y3、Z3-X4、Y4、Z4の2つの線分があります。
2つのセグメント間の最短距離を見つけようとしています。
私は何時間も解決策を探していましたが、それらのすべてが線分ではなく線で機能しているようです。
これをどのように進めるかについてのアイデア、またはfurmulaeのソースはありますか?
1つの基本的なアプローチは、2つの線の間の最短距離を計算することと同じですが、1つ例外があります。
2つの線の間の最短距離を見つけるためのほとんどのアルゴリズムを見ると、各線上の最も近い点を見つけて、それらからの距離を計算していることがわかります。
これをセグメント(または光線)に拡張するコツは、その点が線の端点の1つを超えているかどうかを確認し、そうである場合は、無限線上の実際の最も近い点の代わりに端点を使用します。
具体的なサンプルについては、以下を参照してください。
http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm
すなわち:
http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm#dist3D_Segment_to_Segment()
私はこれをmatlabの観点から回答しますが、他のプログラミング環境を使用することもできます。このソリューションは、任意の数の次元(> = 3)で問題を解決するために有効であることを付け加えます。
空間に2つのラインセグメント、PQとRSがあるとします。いくつかのランダムなポイントセットを次に示します。
> P = randn(1,3)
P =
-0.43256 -1.6656 0.12533
> Q = randn(1,3)
Q =
0.28768 -1.1465 1.1909
> R = randn(1,3)
R =
1.1892 -0.037633 0.32729
> S = randn(1,3)
S =
0.17464 -0.18671 0.72579
無限線PQ(t)は次のように簡単に定義できます。
PQ(u) = P + u*(Q-P)
同様に、
RS(v) = R + v*(S-R)
各ラインについて、パラメータが0または1の場合、ラインの元のエンドポイントの1つが返されることを確認してください。したがって、PQ(0)== P、PQ(1)== Q、RS(0)== R、およびRS(1)== Sであることがわかります。
ラインをパラメトリックに定義するこの方法は、多くのコンテキストで非常に役立ちます。
次に、PQ線に沿って見下ろしていたとしましょう。線分RSから無限線PQまでの距離が最も短い点を見つけることができますか?これは、ラインPQのヌルスペースへの投影によって最も簡単に実行されます。
> N = null(P-Q)
N =
-0.37428 -0.76828
0.9078 -0.18927
-0.18927 0.61149
したがって、null(P-Q)は、ラインPQに直交する2次元部分空間に広がる一対の基底ベクトルです。
> r = (R-P)*N
r =
0.83265 -1.4306
> s = (S-P)*N
s =
1.0016 -0.37923
基本的に私たちが行ったことは、線PQに直交する2次元の部分空間(平面)にベクトルRSを投影することです。 P(ラインPQ上のポイント)を差し引いてrとsを取得することにより、無限のラインがこの投影面の原点を通過するようになります。
そのため、実際には、これを縮小して、投影平面の線rs(v)から原点(0,0)までの最小距離を見つけました。行rs(v)はパラメーターvによって次のように定義されることを思い出してください。
rs(v) = r + v*(s-r)
ラインrs(v)への法線ベクトルは、私たちに必要なものを与えます。元の空間が3次元だったため、これを2次元に減らしたので、簡単に行うことができます。それ以外の場合は、もう一度nullを使用しただけです。この小さなトリックは2次元で機能します。
> n = (s - r)*[0 -1;1 0];
> n = n/norm(n);
nは単位長のベクトルになりました。無限直線rs(v)から原点までの距離は単純です。
> d = dot(n,r)
d =
1.0491
同じ距離を取得するためにsを使用することもできることを確認してください。実際の距離はabs(d)ですが、結局のところ、dはとにかく正でした。
> d = dot(n,s)
d =
1.0491
これからvを決定できますか?はい。原点は、ポイントrとsを結ぶ線からd単位の距離であることを思い出してください。したがって、スカラーvのある値に対して、d n = r + v(sr)と書くことができます。この方程式の各辺のドット積をベクトル(sr)で形成し、vを解きます。
> v = dot(s-r,d*n-r)/dot(s-r,s-r)
v =
1.2024
これは、原点への線分rsの最も近いアプローチが、線分端点の外側で発生したことを示しています。したがって、実際にrsの原点に最も近い点は、点rs(1)= sでした。
投影から戻ると、これは、線分RS上の無限線PQに最も近い点が点Sであることを示しています。
分析には、もう1つのステップがあります。線分PQ上の最も近い点は何ですか?この点は線分内にありますか、それとも端点の外にもありますか?
点Sを線PQに投影します。 (このuの式は、以前に行ったのと同じようなロジックから簡単に導出できます。ここでは、\を使用して作業を行っていることに注意してください。)
> u = (Q-P)'\((S - (S*N)*N') - P)'
u =
0.95903
Uが区間[0,1]にあることを確認してください。問題を解決しました。ラインPQ上のポイントは
> P + u*(Q-P)
ans =
0.25817 -1.1677 1.1473
また、2つの線分上の最も近い点間の距離は
> norm(P + u*(Q-P) - S)
ans =
1.071
もちろん、これらすべてを数行の短いコードに圧縮できます。しかし、それをすべて拡張して、それがどのように機能するかを理解するのに役立ちます。
両方のラインセグメントをパラメーター化して、0から1までの範囲の1つのパラメーターをそれぞれ使用します。次に、両方のライン関数の違いを見つけ、それを変数としてのパラメーターを持つ線形最適化問題の目的関数として使用します。
(0,0,0)から(1,0,0)までの行と(0,1,0)から(0,0,0)までの行があるとします(そうです、私は簡単なものを使用しています) 。行は、tが[0,1]にある(1 * t、0 * t、0 * t)とsが[0,1]にある(0 * s、1 * s、0 * s)のようにパラメーター化できます。 ]、tとは無関係。
次に、||(1 * t、1 * s、0)||を最小化する必要がありますここで、t、sは[0,1]にあります。それは解決するのはかなり簡単な問題です。
線分を無限の線に延長して、2つの線の間の最短距離を見つけてみませんか。次に、最短距離の線分の端点である各線上の点を見つけます。
各ラインのポイントが元のラインセグメント上にある場合は、答えがあります。各線の点が元のセグメント上にない場合、その点は元の線セグメントの終点の1つです。
2つの無限線間の検出に基づいて2つの有限線間の距離を検出し、その無限線を有限線にバインドすると、常に機能するわけではありません。たとえば、この点を試してください
Q=[5 2 0]
P=[2 2 0]
S=[3 3.25 0]
R=[0 3 0]
無限アプローチに基づいて、アルゴリズムは距離計算(距離= 2.2361)のためにRとPを選択しますが、RとSの中間のどこかがPポイントに近い距離になっています。どうやら、RからSの線からPと[2 3.166]を選択すると、1.1666の距離が短くなります。この答えでさえ、正確な計算とPからR Sへの直交線を見つけることにより、より良くなる可能性があります。
まず、延長された線の間を橋渡しする最も近いアプローチのラインセグメントを見つけます。これをLineSeg BRと呼びましょう。
BR.endPt1がLS1に該当し、BR.endPt2がLS2に該当する場合、これで完了です。BRの長さを計算するだけです。
ブリッジBRがLS1と交差するがLS2と交差しない場合は、次の2つの距離の短い方を使用します。
ブリッジBRがLS2と交差するがLS1と交差しない場合は、次の2つの距離のうち短い方を使用します。
これらの条件がいずれも成立しない場合、最も近い距離は、反対側のラインセグメント上のエンドポイントの最も近いペアになります。