Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF: Finding an element along a path

Tags:

math

wpf

2d

I have not marked this question Answered yet.
The current accepted answer got accepted automatically because of the Bounty Time-Limit


With reference to this programming game I am currently building.

As you can see from the above link, I am currently building a game in where user-programmable robots fight autonomously in an arena.


Now, I need a way to detect if a robot has detected another robot in a particular angle (depending on where the turret may be facing):

alt text http://img21.imageshack.us/img21/7839/robotdetectionrg5.jpg

As you can see from the above image, I have drawn a kind of point-of-view of a tank in which I now need to emulate in my game, as to check each point in it to see if another robot is in view.

The bots are just canvases that are constantly translating on the Battle Arena (another canvas).

I know the heading the turret (the way it will be currently facing), and with that, I need to find if there are any bots in its path(and the path should be defined in kind of 'viewpoint' manner, depicted in the image above in the form of the red 'triangle'. I hope the image makes things more clear to what I am trying to convey.

I hope that someone can guide me to what math is involved in achieving this problem.


[UPDATE]

I have tried the calculations that you have told me, but it's not working properly, since as you can see from the image, bot1 shouldn't be able to see Bot2 . Here is an example :

alt text http://img12.imageshack.us/img12/7416/examplebattle2.png

In the above scenario, Bot 1 is checking if he can see Bot 2. Here are the details (according to Waylon Flinn's answer):

angleOfSight = 0.69813170079773179 //in radians (40 degrees)
orientation = 3.3 //Bot1's current heading (191 degrees)

x1 = 518 //Bot1's Center X
y1 = 277 //Bot1's Center Y

x2 = 276 //Bot2's Center X
y2 = 308 //Bot2's Center Y

cx = x2 - x1 = 276 - 518 = -242
cy = y2 - y1 = 308 - 277 =  31

azimuth = Math.Atan2(cy, cx) = 3.0141873380511295

canHit = (azimuth < orientation + angleOfSight/2) && (azimuth > orientation - angleOfSight/2)
       = (3.0141873380511295 < 3.3 + 0.349065850398865895) && (3.0141873380511295 > 3.3 - 0.349065850398865895)
       = true

According to the above calculations, Bot1 can see Bot2, but as you can see from the image, that is not possible, since they are facing different directions.

What am I doing wrong in the above calculations?

like image 245
Andreas Grech Avatar asked Feb 18 '09 01:02

Andreas Grech


3 Answers

The angle between the robots is arctan(x-distance, y-distance) (most platforms provide this 2-argument arctan that does the angle adjustment for you. You then just have to check whether this angle is less than some number away from the current heading.


Edit 2020: Here's a much more complete analysis based on the updated example code in the question and a now-deleted imageshack image.

  1. Atan2: The key function you need to find an angle between two points is atan2. This takes a Y-coordinate and X-coordinate of a vector and returns the angle between that vector and the positive X axis. The value will always be wrapped to lie between -Pi and Pi.

  2. Heading vs Orientation: atan2, and in general all your math functions, work in the "mathematical standard coordinate system", which means an angle of "0" corresponds to directly east, and angles increase counterclockwise. Thus, an "mathematical angle" of Pi / 2 as given by atan2(1, 0) means an orientation of "90 degrees counterclockwise from due east", which matches the point (x=0, y=1). "Heading" is a navigational idea that expresses orientation is a clockwise angle from due north.

    • Analysis: In the now-deleted imageshack image, your "heading" of 191 degrees corresponded to a south-south-west direction. This actually an trigonometric "orientation" of -101 degrees, or -1.76. The first issue in the updated code is therefore conflating "heading" and "orientation". you can get the latter from the former by orientation_degrees = 90 - heading_degrees or orientation_radians = Math.PI / 2 - heading_radians, or alternatively you could specify input orientations in the mathematical coordinate system rather than the nautical heading coordinate system.
  3. Checking that an angle lies between two others: Checking that an vector lies between two other vectors is not as simple as checking that the numeric angle value is between, because of the way the angles wrap at Pi/-Pi.

    • Analysis: in your example, the orientation is 3.3, the right edge of view is orientation 2.95, the left edge of view is 3.65. The calculated azimith is 3.0141873380511295, which happens to be correct (it does lie between). However, this would fail for azimuth values like -3, which should be calculated as "hit". See Calculating if an angle is between two angles for solutions.
like image 51
Jimmy Avatar answered Nov 07 '22 15:11

Jimmy


Calculate the relative angle and distance of each robot relative to the current one. If the angle is within some threshold of the current heading and within the max view range, then it can see it.

The only tricky thing will be handling the boundary case where the angle goes from 2pi radians to 0.

like image 1
geofftnz Avatar answered Nov 07 '22 17:11

geofftnz


Something like this within your bot's class (C# code):

/// <summary>
/// Check to see if another bot is visible from this bot's point of view.
/// </summary>
/// <param name="other">The other bot to look for.</param>
/// <returns>True iff <paramref name="other"/> is visible for this bot with the current turret angle.</returns>
private bool Sees(Bot other)
{
    // Get the actual angle of the tangent between the bots.
    var actualAngle = Math.Atan2(this.X - other.X, this.Y - other.Y) * 180/Math.PI + 360;

    // Compare that angle to a the turret angle +/- the field of vision.
    var minVisibleAngle = (actualAngle - (FOV_ANGLE / 2) + 360);
    var maxVisibleAngle = (actualAngle + (FOV_ANGLE / 2) + 360); 
    if (this.TurretAngle >= minVisibleAngle && this.TurretAngle <= maxVisibleAngle)
    {
        return true;
    }
    return false;
}

Notes:

  • The +360's are there to force any negative angles to their corresponding positive values and to shift the boundary case of angle 0 to somewhere easier to range test.
  • This might be doable using only radian angles but I think they're dirty and hard to read :/
  • See the Math.Atan2 documentation for more details.
  • I highly recommend looking into the XNA Framework, as it's created with game design in mind. However, it doesn't use WPF.

This assumes that:

  • there are no obstacles to obstruct the view
  • Bot class has X and Y properties
  • The X and Y properties are at the center of the bot.
  • Bot class a TurretAngle property which denotes the turret's positive angle relative to the x-axis, counterclockwise.
  • Bot class has a static const angle called FOV_ANGLE denoting the turret's field of vision.

Disclaimer: This is not tested or even checked to compile, adapt it as necessary.

like image 1
Ben S Avatar answered Nov 07 '22 17:11

Ben S