2012-05-26 9 views
6

であるかどうかを確認し考えてみましょう:ポイントは3D空間でコーンの内側に

  • X(x1,y1,z1)私はそれがコーンの内側にあるかどうかを確認する必要がポイント。
  • M(x2,y2,z2)円錐の頂点。 (円錐の頂点)
  • N(x3,y3,z3)円錐の底の中央にある点。

私は、ポイントXがコーン上にある場合、それはこの式を検証する必要があることが分かった:

ドットが2つのベクトルの内積であり、アルファは、これらの間の角度である
cos(alfa) * ||X-M|| * ||N|| = dot(X-M,N) 

2つのベクトル。

式に基づいて、私はそれを計算:

X-M = (x1-x2,y1-y2,z1-z2) 

だから、

cos(alfa) 
    * Math.sqrt((x1-x2)^2+(y1-y2)^2+(z1-z2)^2) 
    * Math.sqrt(x3^2 + y3^2+z3^2) 
= x3(x1-x2) + y3(y1-y2) + z3(z1-z2) 

は生憎上記の計算は私に間違った結果を与えているようです。私は間違って何をしていますか?

また、Xが円錐の内側にあるかどうかを確認するには、=の代わりに<=を入力する必要があります。これは正しいです?

この使い方は次のとおりです。オブジェクトが「ビュー」内にあるときに機関銃が発砲しなければならないゲームを開発します。このビューは円錐です。コーンの頂点は機関銃の中にあり、コーンの基部はある距離先にあります。このコーンに入っている物体があれば、マシンガンがそれを撃つでしょう。

答えて

11

私はTimと全く同意します:答えを得るためには、コーンの「角度」(絞り)が必要です。

コーディングをしましょう! hereからいくつかの用語を使用します。

結果-与える機能:以下

/** 
* @param x coordinates of point to be tested 
* @param t coordinates of apex point of cone 
* @param b coordinates of center of basement circle 
* @param aperture in radians 
*/ 
static public boolean isLyingInCone(float[] x, float[] t, float[] b, 
            float aperture){ 

    // This is for our convenience 
    float halfAperture = aperture/2.f; 

    // Vector pointing to X point from apex 
    float[] apexToXVect = dif(t,x); 

    // Vector pointing from apex to circle-center point. 
    float[] axisVect = dif(t,b); 

    // X is lying in cone only if it's lying in 
    // infinite version of its cone -- that is, 
    // not limited by "round basement". 
    // We'll use dotProd() to 
    // determine angle between apexToXVect and axis. 
    boolean isInInfiniteCone = dotProd(apexToXVect,axisVect) 
           /magn(apexToXVect)/magn(axisVect) 
           > 
           // We can safely compare cos() of angles 
           // between vectors instead of bare angles. 
           Math.cos(halfAperture); 


    if(!isInInfiniteCone) return false; 

    // X is contained in cone only if projection of apexToXVect to axis 
    // is shorter than axis. 
    // We'll use dotProd() to figure projection length. 
    boolean isUnderRoundCap = dotProd(apexToXVect,axisVect) 
           /magn(axisVect) 
           < 
           magn(axisVect); 
    return isUnderRoundCap; 
} 

ベクトルを操作するために、上のコードで必要とされる、基本的な機能の私の速い実装です。

static public float dotProd(float[] a, float[] b){ 
    return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]; 
} 

static public float[] dif(float[] a, float[] b){ 
    return (new float[]{ 
      a[0]-b[0], 
      a[1]-b[1], 
      a[2]-b[2] 
    }); 
} 

static public float magn(float[] a){ 
    return (float) (Math.sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2])); 
} 

楽しくお楽しみください!

+0

これはすばらしい答えであり、私は生産ソリューションのように見えるものに非常に近いです! – Tim

+0

フリークレットありがとう!魅力のように動作します。 –

+0

あなたはそれが好き、非常にうれしい! – fyodorananiev

1

あなたの差ベクトル(X-M)とあなたの中心ベクトル(N)の間の角度が(あなたが質問で指定しなかった)あなたの円錐の角度以下かどうかを確認する必要があります。これは、位置ベクトル(X)が無限の円錐の内側にあるかどうかを知らせます。距離(必要な場合)を確認することもできます。したがって、Nの正規化(長さ1のベクトルに変換)し、長さを別々に保存することもできます。次に、norm(X-M)と長さを比較すると、丸底円錐が得られます(その名前は確信していますが、わかりません)。

編集:逆余弦を忘れて、ドット積はnorm(U)*norm(V)*cos(Angle)と等しくなりますので、角度を比較する操作を逆にする必要があります。この場合、正と負の角度を均等に比較したいが、そのことに注意するので、acosはうまくいくはずです。

編集:ラジアン。

+0

30ラジアンは、円錐の半角に対して少し大きいようです。 –

+0

@AndrewMortonありがとう!私は今日、私の思考上限を身につけている。 – Tim

+0

数式は2つの部分を持つ円錐を考慮していますか?おそらく、銃は同時に後方に発射しない;) –

関連する問題