Check if the point is inside the cone in three-dimensional space

Consider:

  • X(x1,y1,z1) point I need to check if it is inside the cone.
  • M(x2,y2,z2) vertex of the cone. (top point of the cone)
  • N(x3,y3,z3) point in the middle of the base of the cone.

I found out that if point X is on a cone, then it is necessary to check this equation:

 cos(alfa) * ||XM|| * ||N|| = dot(XM,N) 

Where the point is the scalar product of two vectors, and alfa is the angle between the two vectors.

Based on the formula, I calculated that:

 XM = (x1-x2,y1-y2,z1-z2) 

So,

 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) 

Unfortunately, the above calculations seem to give me the wrong results. What am I doing wrong?

I also suspect that to check whether X inside the cone, I have to put <= instead of = in the formula. Is it correct?

Using this: I am developing a game in which a machine gun should start shooting when an object is in its β€œview”. This view will be a cone. The top of the cone will be in the machine gun, the base of the cone will be at some known distance in front. Any object that enters this cone, a machine gun will shoot him.

+6
source share
2 answers

I completely agree with Tim: we need the "angle" (aperture) of the cone to get an answer.

Let's do some coding! I will use some terminology from here .

Result Creation Function:

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

Below are my quick implementations of the basic functions required by the top code for vector management.

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

Good luck

+11
source

You need to check if the angle between your difference vector (XM) and your central vector (N) is less than the angle of your cone (which you did not specify in the question). This will tell you if the position vector (X) is inside the infinite cone, and you can also check the distance (if you want). Thus,

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

For performance, you can also normalize N (convert it to a vector with a length of 1) and save the length separately. Then you can compare norm(XM) with length, giving you a round-bottom cone (for which I am sure that the name exists, but I do not know that).

Edit: Forgotten inverse cosine, the point product is norm(U)*norm(V)*cos(Angle) , so we must invert this operation to compare angles. In this case, acos must be accurate, because we want the positive and negative angles to be compared equally, but watch out for this.

Edit: Radians.

+1
source

Source: https://habr.com/ru/post/916755/


All Articles