• ベストアンサー

3次元空間内での線分の交差判定について

はじめまして。 3D関係のプログラムを組む上で、線分同士の判定を行う必要があるのですが 数学の知識が乏しく困っています。 3次元空間内の線分ABとCDが交差しているか判定し、 交差していればその交点を求めたいのです。 2次元の場合はできたのですが、3次元になるとどうやって計算すればよいのか わかりません。(交差以外に、ねじれの位置関係があるんですよね?) どなたか教えていただけると助かります。

質問者が選んだベストアンサー

  • ベストアンサー
  • ametsuchi
  • ベストアンサー率31% (81/257)
回答No.2

1)一般に「捩れの位置」になりますから、互いに最短の位置を求める問題に帰着します。a-kumaさんの言われるような連立一次方程式では未知数が2つ、式がx,y,z3つとなるので解けません。2次元ならyosizoさんの言われるように未知数と式の数が2つで簡単に解けます。 2)線分AB、CDの何れかの長さが<ε以下、または、線分AB、CDはほぼ平行ならゼロ割を起こすか答えが求まっても答えの精度が著しく低下します。このチェックも実際のプログラムでは絶対に必要です。 3)で、以下、2)のチェック済みであると仮定して.....。 4)たまたま最近3D-CAD用に作ったもので数式の求めた方を忘れてしまったが、 // t0:AB方向単位ベクトル、t1:CD方向単位ベクトル、として、 // float spd = <t0・t1>即ち、ベクトルt0とt1の内積 float det = spd*spd - 1.0f; // spd:AB方向単位ベクトル v01 = C - A; //3Dベクトル (C-A) u0 = (spd*<v01・t1> - <v01・t0>) / det; u1 = (<v01・t0> - spd*<v01・t1>) / det; として、パラメータ、u0,u1が求まります。ここに、 u0:AB方向パラメータ、u0=0の時、q0(u0)=Aで、u0はAからの距離を表わす。 ■q0(u0)=A+u0*t0...............Equ.1) u1:CD方向パラメータ、u1=0の時、q1(u1)=Cで、u1はCからの距離を表わす。 ■q1(u1)=C+u1*t1...............Equ.2) これで、捩れの位置に2点求まるのですが、 ・2点が距離の許容誤差よりも離れていたら、エラーとする。 ・2点が距離の許容誤差以内なら、2点の中点を取る。 ・中点がいやなら、重みを掛ける(場合もある)。 この説明で不十分ならあとで補足します。

その他の回答 (6)

  • ametsuchi
  • ベストアンサー率31% (81/257)
回答No.7

motsuanさん、アドバイスありがとうございます。 >外積を直接とっちえばいいものを ..中略...のような周りくどいことをやらないと 答えがもとめられないのかちょっと不思議に思います 一般に外積計算は内積計算に比べて「コストのかかる」計算であり、なるべく使わないようにしているだけです。motsuanさんのやり方の分かり易さや、「外積計算」の有用性については百も承知しているつもりです。 もし、私のやり方の方が「コストのかかる」計算であったなら、折角今回初めて「専門家」を自称したのにおハズカシい限りで、訂正させてもらいます。 motsuanさんのやり方も私がいう「一般性のある」やり方で、敬意を表します。3D幾何計算ライブラリなどでは直線(線分)同士は、「交点」ではなく「最近点」として求めるのが普通です。

yosizo
質問者

お礼

返事が遅くなり、失礼しました。 詳しい解説、ありがとうございます。 >3D幾何計算ライブラリなどでは直線(線分)同士は、「交点」ではなく「最近点」として求めるのが普通です。 そうなんですか、しりませんでした。勉強になります。 今回の皆さんの回答を参考にしてプログラムに落とし込んでみます。

  • motsuan
  • ベストアンサー率40% (54/135)
回答No.6

もうすでに完全に説明されているようですが、 なんとなく私も前に計算してなるほどと なんか関心してしまったことがあるので (他の方からみると見苦しいとは思いますが) 書きこませてください。 ametsuchiさんのアルゴリズムは 多分以下のように求めれば すべてベクトル演算で求められると思います。 (ねじれの位置の場合も線分の中に対応する点が  あれば一番近づいている点をあたえると思います。) ベクトルを[v]と表します。 2つ直線[p](u)、[q](v)をパラメータ表示で表します。 それぞれ定点を[p0]、[q0]、大きさが任意の方向ベクトルを[s]、[t]とすると [p](u)=[p0]+[s]u [q](v)=[q0]+[t]v と表せます。このとき [p](u)-[q](v)=0 となる u、v があればそれが交点を与えます。 3次元空間で交わる場合には、 当然どの平面に射影したとしても(どっちの方角から見ても) 交点を結んでいなくてはなりません。 したがって適当な平面へ射影した場合の交点を求めれば良いわけです。 これがkent-mildsのおっしゃっていることで やっぱり一番現実的なのでしょうね。 でも、なんとなく、 一番近づく点の特殊な場合が交点であって欲しい という気持ちを収めるために以下のように基準面を選びます。 すなわち、一番近づく点が射影したときに交点となる平面は [s]、[t]のベクトルで張る平面ですから、この平面を基準に考えます。 (以下、内積を・で、外積を×で表します。) [p](u)と[q](v)を[s]、[t]のベクトルで張る平面に射影すると 1点に重なるためには[p](u)-[q](v)が面の法線と平行でなくてはなりません。 したがって、([p](u)-[q](v))×[s]と([p](u)-[q](v))×[t]は 面に平行なベクトルになりますから、これが[s]×[t]と直行する必要があります。 すなわち、 ([s]×[t])・(([p](u)-[q](v))×[s])=0・・・(*) ([s]×[t])・(([p](u)-[q](v))×[t])=0 が求める点の条件で、これから u, v が決まります。たとえば u を求めると、 ([p](u)-[q](v))×[t]  =([p0]-[q0])×[t] + [s]×[t]u =0 両辺に[s]×[t]を掛けて ([s]×[t])・(([p0]-[q0])×[t] )+([s]×[t])・([s]×[t])u =0。 これを解いて u =-([s]×[t])・(([p0]-[q0])×[t] )/([s]×[t])・([s]×[t])。 同様に(tとsを入れ替えて)、 v =([s]×[t])・(([p0]-[q0])×[s] )/([s]×[t])・([s]×[t]) となります。 わたしはなんで ([p](u)-[q](v))と[s]×[t]の外積を直接とっちえばいいものを (*)のような周りくどいことをやらないと 答えがもとめられないのかちょっと不思議に思います。 以上です。お邪魔しました。

yosizo
質問者

お礼

返事が遅くなり、失礼しました。 詳しい解説、ありがとうございます。 今回の皆さんの回答を参考にしてプログラムに落とし込んでみます。

  • ametsuchi
  • ベストアンサー率31% (81/257)
回答No.5

すいません。もう2つ補足。 1)a-kumaさんらの方法でもできないことはないのですが、一般性がなく、式3つのうちどの2つを選択するか決めなくてはいけません。私の方法なら、場合分けも不要で答えは一意的に求まります。 2)線分上に求まるか否かのチェックはa-kumaさんの言われるとおりです。パラメータの取り方が違っていますが、本質的な差異ではありません。私が示したパラメータだと、 ■0<= u0,u1 <=線分長 だとOKです。 ・しかし実際のプログラムでは、 ■-tol<= u0,u1 <=線分長+tol のようにすることが多いです。ここに,tolとは距離の許容誤差です。 ※何か不明な点があったら聞いて下さい。

  • ametsuchi
  • ベストアンサー率31% (81/257)
回答No.4

補足します。 2線分上の点はパラメータで表現すると、 ■q0(u0)=A+u0*t0...............Equ.1) ■q1(u1)=C+u1*t1...............Equ.2) ですが、 ・ベクトルq1(u0)-q0(u1)と、ベクトルt0、が直交 ・ベクトルq1(u0)-q0(u1)と、ベクトルt1、が直交 という条件を課すと、2つのパラメータ、u0,u1に関する2元一次連立方程式になります。これを解いたのが、先程の、 float det = spd*spd - 1.0f; // spd:AB方向単位ベクトル v01 = C - A; //3Dベクトル (C-A) u0 = (spd*<v01・t1> - <v01・t0>) / det; u1 = (<v01・t0> - spd*<v01・t1>) / det; です。

yosizo
質問者

お礼

すみません、これは↓のNo3 Kent-mild さんへのお礼です。 #ここの使い方に慣れてなくて、意味のない書き込みをしてしまいました・・・ 返事が遅れて大変失礼しました。 みなさんからの回答を参考にしてプログラムを組んでみようと思います。 ありがとうございました。

回答No.3

プログラムで簡単に組める方法で説明します。 2次元ではできてらっしゃるようなので、2次元の説明は省略します。 3次元空間が(x,y,z)座標で定義されている場合、 xy平面上の交点のz座標が同一なら交差、一致しなければねじれです。 交点の座標はすぐでるのはわかりますよね?

yosizo
質問者

お礼

3D幾何計算ライブラリなどでは直線(線分)同士は、「交点」ではなく「最近点」として求めるのが普通です。

  • a-kuma
  • ベストアンサー率50% (1122/2211)
回答No.1

線分AB上の任意の点Pはベクトル表現で p = t×a + (1 - t)×b   但し 0≦t≦1 です(本当は、記号の上に矢印を書きたいところなんですが)。 同様に、線分CD上の任意の点Qは q = s×c + (1 - s)×d   但し 0≦s≦1 です。線分が交差しているということは、PとQが同一になるという ことですから、 p = q を満たす t と s が有るかどうか、ということですね。 3次元であれば、各要素毎に3本の式ができ、変数が二つですから 簡単ですね。 例えば、x と y について、t と s についての連立方程式を解いて、 それぞれ0~1に入っていなければ、交差してない。 もし、その範囲に入っていたとすれば、z の式に代入してみて 等式を満たすようであれば、交差する、という判定でしょうか。

yosizo
質問者

お礼

返事が遅くなり、失礼しました。 詳しい解説、ありがとうございます。 今回の皆さんの回答を参考にしてプログラムに落とし込んでみます。

関連するQ&A

  • 線分の交点の保持

    いつもお世話になってます。 2つ以上の線分が2次元上にあって、線分が交差した場合それぞれの交点を保ちながらも移動し、交点で回転しながら他の線分とも衝突判定を行う、というアルゴリズムを考えているのですがなかなかうまくいかず悩んでいます。 最終的にはたくさんの線分がくっついて、くねくねしながら移動するようなイメージです。 速度を同じにして、交点を軸に回転させてみたのですが、3本目の線分が交差したときうまくいかなくなってしまいました・・。 ぜひ皆さんの力を貸してください。よろしくお願いします。

  • ★点と線分の距離??★

    いつもお世話になっています。 プログラミングで困っています。どなたか基本的な数学からご教授ください。 (1)線分ABに対して点Pから垂線を下ろすことが出来るかどうかの判定をするには? (2)垂線と線分との交点の座標を求めるには? (3)垂線と線分の交点の距離を求めるには これらの処理を出来るだけ早く処理したいのです。 あと、確認なのですが 「線分に垂線を下ろすことができるのであれば、その交点が点に最も近い」 でいいのですよね。 よろしくお願いします。

  • 3次元空間上の2点を結ぶ線分の中点を知りたい

    3次元空間上の点A(x1, y1, z1)と点B(x2, y2 z2)を結んで出来る線分の中点を知りたいのですが、 完全な文系出身であまり数学に詳しくないため、公式の見方がよくわかりません。 Wikipediaの中点のページにあるn次元ユークリッド空間上の中点の公式がそれのようですが、 「n 次元ユークリッド空間上の2点 A, B を直交座標系であらわし、それぞれを (a0, ..., an-1), (b0, ..., bn-1) とすると」 の時点ですでに理解できないので、単純な公式で教えて下さると助かります。

  • 次元と次元空間

    ふと思ったのですが物理で多次元って いうのがあるようなのですが あれは多次元空間のことを言ってる のですか? 例えば超ひも理論は10次元?とか 聞きますが それら10個の軸は 互いに内積0の関係にある10次元空間内の 理論なんでしょうか? 以前 水素原子モデルの電子運動を 計算したのですがそこでは11次元が 出てきて、その次元要素は確か 位置の3次元 軌道角運動量の3次元 角運動量の3次元 スピン角運動量の2次元 の3+3+3+2=11で 3次元空間内での11次元表記と 理解したのですが超ひもとかも こんな感じなんでしょうか? できれば 実際に計算で理解された方の 回答がほしいです

  • 3次元空間におけるアフィン変換について

    3次元空間で直線を軸とした回転運動している物体の座標の特定をしたいと考えています。 最終的にX、Y、Z軸を軸とする回転角度を得ることができればと思っています。 具体的に以下のような数学の問題があったとして、 どう解いていくかを経緯も含めて教えていただきたいのです。 [設問] 3次元空間に点A(x,y,z) = (0,0,0)と点B(100,-100,100)の2点がある。 また直線ABに含まれない点C(50,-50,0)がある。 点Cを含み直線ABに直交する平面と直線ABとの交点をDとし 点Cが線分CDを半径として当該平面上の円を一定の速度で回転している。 このとき点Cの円周上の回転角度をaとする時、 点Cのx、Y、Z軸それぞれを軸とした回転角度をaを用いて表しなさい

  • 線分同士の交点の判定

    線分の交差判定についてネットで調べていたら、以下のような処理で できると書かれていたページがあったのですが、どうしても理解する事が できません。 もしできれば、解説を頂いてもいいでしょうか。 よろしくお願いします。 //2次元での線分と線分の交差判定と交点 BOOL CheckCrossLine(CONST D3DXVECTOR2* pvA1,           CONST D3DXVECTOR2* pvA2,           CONST D3DXVECTOR2* pvB1,           CONST D3DXVECTOR2* pvB2,           D3DXVECTOR2* pvOut) { D3DXVECTOR2 v1 = *pvA1 - *pvB1; D3DXVECTOR2 vA = *pvA2 - *pvA1; D3DXVECTOR2 vB = *pvB2 - *pvB1; if (*pvA1 != *pvA2) ; else return FALSE;//線分が点のときは交差していないとする if (*pvB1 != *pvB2) ; else return FALSE;//線分が点のときは交差していないとする FLOAT fDeno = vA.x * vB.y - vA.y * vB.x;//外積の長さ //分母が0で、平行なときは if (fDeno != 0.0f) ; else return FALSE;//交差していないことにする FLOAT t = (v1.y * vB.x - v1.x * vB.y) / fDeno; FLOAT s = (v1.y * vA.x - v1.x * vA.y) / fDeno; if (t < 0.0f || t > 1.0f || s < 0.0f || s > 1.0f) return FALSE;//交差していない else { //交点を返す pvOut->x = vA.x * t + pvA1->x; pvOut->y = vA.y * t + pvA1->y; return TRUE;//交差 }

  • 3つの線分は、同じ点で交わることをベクトルを用いて示す問題について

    「四面体ABCDがある。互いにねじれの位置にある辺の中点を結ぶ3つの線分は同じ点で交わることを示せ。」 という問題があり、この正解答として掲載されている解法が理解できません。 その解法の流れは、 まずAB、CDの中点をP、Qとしたとき、PQの中点の位置ベクトルを求め、同様にその他のねじれの位置にある辺の中点を結ぶ辺の中点を求め、結果的にその中点は同じ位置ベクトル「($a+$b+$c+$d)/4」($はベクトル記号とする)であるから同じ点で交わる。 としていますが、僕にはPQの「中点」が交点だという推測ができません。 なぜ「交点」はねじれの位置にある辺の中点を結ぶそれぞれ辺の「中点」だと事前に推測できるのですか? その点について整理したいです。お手数ですが、そのための助言などをしていただきたいです。 よろしくお願い致します。

  • 多角形の自己交差を判定するには?

    3D空間にある平面多角形で、頂点が1000個ぐらいの多角形を想定しています。 これの多角形の辺同士で交点の有無により、自己交差を判定すると時間がかかってしまいます。 もっと、効率の良い方法はありますか?

  • 線分と線分が交わる条件を簡単に求める方法ってないでしょうか?

    線分と線分が交わる条件を簡単に求める方法ってないでしょうか? 線分が2つ(8つの値)があります (ax1,ay1)-(ax2,ay2) (bx1,by1)-(bx1,by1) この8つの値の大小関係だけで交差するかどうかの判定って 可能でしょうか? 直線の式y = ax + bを2つをわりだし その解がそれぞれの線分の範囲内にあるかで求めていたのですが 線分の数が多いためパフォーマンスに影響がでてきてしまいました。 (C言語で計算させています。) 数学は苦手なので、困っております。 或いは良い案があればお願いします

  • 2つの線分の最短距離

    2つの線分の衝突判定をして、そこから色々な形の当たり判定を作っていこうと思っているのですが・・・ 3次元上で、タイトルのものをどう計算して出したらいいのか分かりません。 本もいくつか読んでみましたが、数式しか載っていなくて、プログラムでどう表現したらいいのか・・・ ご教授願います。