Omnimaga

General Discussion => Technology and Development => Computer Programming => Topic started by: Scipi on January 20, 2014, 06:19:26 pm

Title: Finding if a point falls within an angle
Post by: Scipi on January 20, 2014, 06:19:26 pm
Hello everyone.

I've been working on a project and I am running into a bug with implementing sight for bots within the program. Basically, for each eye on an bot I have an angle for direction and a field of view, both represented in degrees. I want to find if a bot falls within sight of another, adding a buffer should only part of a bot be visible.

Here's the code I have:

Code: (java) [Select]
private boolean inFOV2(Bot b, double uAngle, double lAngle){

double dist = Math.sqrt((xPos - b.xPos)*(xPos - b.xPos) + (yPos - b.yPos)*(yPos - b.yPos));

if(dist < 0){
    dist = .001;
}

double buffer = Math.toDegrees(Math.asin(b.radius/dist));

double angle = Math.toDegrees(Math.atan2(b.yPos - yPos, b.xPos - xPos));

uAngle += buffer;
lAngle -= buffer;

return (uAngle - angle >= 0 && lAngle - angle <= 0);
    }

//Called via

inFOV2(b, angle + FOV, angle - FOV)

This doesn't seem to be working properly. Sometimes it detects it sees another bot when it doesn't, or vice versa. I have no idea where I am going wrong here, so any insight would be greatly appreciated. ^_^

Thanks
Title: Re: Finding if a point falls within an angle
Post by: pimathbrainiac on January 20, 2014, 08:08:38 pm
hmm, what's the buffer there for?
Title: Re: Finding if a point falls within an angle
Post by: Scipi on January 20, 2014, 08:34:31 pm
There are some cases where only part of a circle is "visible," so the buffer is the angle to increase/decrease the view by to cover any circle overlaying the view at a given distance.

Here:

(https://dl.dropboxusercontent.com/u/10573921/BufferExplaination.png)
Title: Re: Finding if a point falls within an angle
Post by: pimathbrainiac on January 20, 2014, 08:54:39 pm
I need more information. Will you please explain your coodinate system and how your code is intended to work?
Title: Re: Finding if a point falls within an angle
Post by: Scipi on January 20, 2014, 09:44:31 pm
Coordinates are given in floating point values in an (x,y) plane. (0, 0) is the top left hand corner y increases as you go down the screen.

The code provided is supposed to determine if the angle of a given bot relative to the bot doing the testing, falls within two angles which represent the limits of the bot's sight.

Code: [Select]
double angle = Math.toDegrees(Math.atan2(b.yPos - yPos, b.xPos - xPos));
This gets the angle between the bot doing the test, and the bot being tested on.

After that, we add the buffer to account for if part of the bot falls within sight, but not the origin. This part works as intended.

We then see if the upper angle is greater than the angle between the two bots, and if the lower one is less than. This is the part I believe is not working correctly.
Title: Re: Finding if a point falls within an angle
Post by: pimathbrainiac on January 20, 2014, 09:52:19 pm
Have you considered changing the ">=" and "<=" to ">" and "<"

Just using a plain English to Java translation often times works to solve problems I have.

If that doesn't work, check the parenthesizes on the return. You might not have put enough where you want them.
Title: Re: Finding if a point falls within an angle
Post by: dinosteven on January 20, 2014, 10:04:44 pm
Code: (java) [Select]
double dist = Math.sqrt((xPos - b.xPos)*(xPos - b.xPos) + (yPos - b.yPos)*(yPos - b.yPos));

if(dist < 0){
    dist = .001;
}
Erm, distance from a sqrt shouldn't give you a negative... I don't believe that if conditional will ever be fulfilled.
Title: Re: Finding if a point falls within an angle
Post by: calc84maniac on January 20, 2014, 10:05:41 pm
You can use the dot product of the viewing direction vector and the vector between the two bots. The direction vector should be <cos(viewangle), sin(viewangle)> and the vector between the bots should be <b.xPos - xPos, b.yPos - yPos>. The dot product of these two vectors, (b.xPos - xPos)*cos(viewangle) + (b.yPos - yPos)*sin(viewangle), is equal to the magnitude of the two vectors times the cosine of the angle between them. The magnitude of the first is 1, and the magnitude of the second is the distance between the bots. So you can divide the aforementioned dot product by the distance between the bots and get the cosine of the angle between the view direction and the other bot. Then, you can just compare it to the cosine of half the field of view. Hopefully this all makes sense.
Title: Re: Finding if a point falls within an angle
Post by: Scipi on January 20, 2014, 10:11:53 pm
Code: (java) [Select]
double dist = Math.sqrt((xPos - b.xPos)*(xPos - b.xPos) + (yPos - b.yPos)*(yPos - b.yPos));

if(dist < 0){
   dist = .001;
}
Erm, distance from a sqrt shouldn't give you a negative... I don't believe that if conditional will ever be fulfilled.

Good catch, that was supposed to be ==.

You can use the dot product of the viewing direction vector and the vector between the two bots. The direction vector should be <cos(viewangle), sin(viewangle)> and the vector between the bots should be <b.xPos - xPos, b.yPos - yPos>. The dot product of these two vectors, (b.xPos - xPos)*cos(viewangle) + (b.yPos - yPos)*sin(viewangle), is equal to the magnitude of the two vectors times the cosine of the angle between them. The magnitude of the first is 1, and the magnitude of the second is the distance between the bots. So you can divide the aforementioned dot product by the distance between the bots and get the cosine of the angle between the view direction and the other bot. Then, you can just compare it to the cosine of half the field of view. Hopefully this all makes sense.

I was given a similar solution a few days ago by a colleague. I have an attempt to implement what he said under this code:

Code: [Select]
private boolean inFOV(Bot b, double uAngle, double lAngle){
double x1 = Math.cos(Math.toRadians(uAngle));
double y1 = Math.sin(Math.toRadians(uAngle));
double x2 = Math.cos(Math.toRadians(lAngle));
double y2 = Math.sin(Math.toRadians(lAngle));

double uDist = y1 * b.xPos + -x1 * b.yPos;
double lDist = -y2 * b.xPos + x2 * b.yPos;

return (uDist > b.radius && lDist < b.radius);
    }

I'll recode it to try and implement what you suggested. Seems like what I need.

Edit:

Calc84's method solved my issue. Damn, I really need to take a look into vectors >_<

Here's the working code:

Code: [Select]
private boolean inFOV3(Bot b, double angle, double FOV){
double x1 = Math.cos(Math.toRadians(angle));
double y1 = Math.sin(Math.toRadians(angle));
double dist = Math.sqrt((xPos - b.xPos)*(xPos - b.xPos) + (yPos - b.yPos)*(yPos - b.yPos));
double dx = b.xPos - xPos;
double dy = b.yPos - yPos;

if(dist == 0){
    dist = .001;
}

//(b.xPos - xPos)*cos(viewangle) + (b.yPos - yPos)*sin(viewangle)


double dotP = (b.xPos - xPos)*x1 + (b.yPos - yPos)*y1;
double dAngle = dotP / dist;
double halfField = Math.cos(FOV);

return (dAngle >= halfField);
    }
Title: Re: Finding if a point falls within an angle
Post by: dinosteven on January 20, 2014, 10:29:11 pm
EDIT: Geometry fail there.
Title: Re: Finding if a point falls within an angle
Post by: Scipi on January 20, 2014, 10:38:56 pm
Code: (java) [Select]
double buffer = Math.toDegrees(Math.asin(b.radius/dist));
If I'm correct, the dist you calculated is the distance from the centers... radius/distance is, by your picture, opposite/adjacent, not opposite/hypotenuse, so I think you should be using atan there. That might be your problem. This results in a smaller buffer, which would explain why some objects inside don't work, but not why some objects outside work. Have you tried doing it without accounting for a buffer?

Edit: Ninja'd, nvm.

The distance between bots is actually the hypotenuse, although it doesn't show well in the picture. It's because the line running from the center of the home bot to the other bot's perimeter is a tangent.