考虑:
-
X(x1,y1,z1)
我需要验证,如果它是一个圆锥体里面的点。 -
M(x2,y2,z2)
圆锥的顶点。 (圆锥体的顶点) -
N(x3,y3,z3)
在锥体的基部的中间的点。
我发现,如果一个点的X是在圆锥体,它需要验证这个等式:
cos(alfa) * ||X-M|| * ||N|| = dot(X-M,N)
其中点是2个向量的标量积,和阿尔法是这些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
是锥体内,我必须把<=
代替的=
在公式中。 它是否正确?
这种用法是:我开发一个游戏,一个机枪有当一个物体在其“观点”,开始射击。 这种观点将是一个圆锥体。 锥的顶点将在机枪的圆锥体的底部将在一些已知的距离领先。 进入这个圆锥的任何对象,机枪将拍摄它。
我完全同意添:我们需要锥的“角”(孔径)来得到答案。
让我们做一些编码呢! 我将使用一些术语来自这里 。
结果,使功能:
/**
* @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]));
}
玩得开心!
你需要检查你的差向量(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(XM)
的长度,给你一个圆底锥(为此我敢肯定的名称存在,但我不知道它)。
编辑:忘记反余弦,内积等于norm(U)*norm(V)*cos(Angle)
所以我们必须颠倒该操作比较的角度。 在这种情况下,ACOS应该是很好的,因为我们要正面和负面的角度来比较平等,但要注意这一点。
编辑:弧度。