7

検討:

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

点 X が円錐上にある場合、次の方程式を検証する必要があることがわかりました。

cos(alfa) * ||X-M|| * ||N|| = dot(X-M,N)

ここで、dot は 2 つのベクトルのスカラー積で、alfa はこれら 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を入れなければならないと思います。これは正しいです?<==

これの使用法は次のとおりです。オブジェクトが「ビュー」にあるときに機関銃が発砲を開始する必要があるゲームを開発します。このビューは円錐になります。円錐の頂点は機関銃の中にあり、円錐の基部は既知の距離先にあります。このコーンに物体が入ると、機関銃がそれを撃ちます。

4

2 に答える 2

11

私はティムに完全に同意します。答えを得るには、円錐の「角度」(開口)が必要です。

それではコーディングをしましょう!ここからいくつかの用語を使用します。

結果を与える機能:

/**
 * @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]));
}

楽しむ!

于 2012-05-27T08:51:58.863 に答える
1

差ベクトル (XM) と中心ベクトル (N) の間の角度が円錐の角度 (質問で指定していない) 以下であるかどうかを確認する必要があります。これにより、位置ベクトル (X) が無限円錐の内側にあるかどうかがわかります。必要に応じて、距離も確認できます。そう、

float theta = PI/6; //half angle of cone
if (acos(dot(X-M, N)/(norm(X-M)*norm(N)) <= theta) doSomething();

パフォーマンスのために、N を正規化 (長さ 1 のベクトルに変換) し、長さを個別に保存することもできます。次に、長さを比較norm(X-M)して、丸い底の円錐を与えることができます (名前が存在することは確かですが、私は知りません)。

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

編集:ラジアン。

于 2012-05-26T17:15:21.563 に答える