Calculating intercept angle
(this is a cross-post from the math and physics forum - haven''t received any definitive answers from there yet so thought I''d try here. Delete if necessary.)
I was wondering whether anyone has a non-iterative formula for finding the angle one should fire a constant velocity projectile in order to hit another constant velocity projectile (in 2d)?
If there is definitely no such formula, what''s the best way to write an iterative one?
And yes I''ve tried google numerous times, and search on these forums is still broken.
Any help would be much appreciated.
I can't provide any real formulas at this time, but here's how it works.
You know that the point you're going to fire at is somewhere along the straight-line trajectory of the target object.
If you know the velocity of your projectile, and the velocity of the target object, then you just solve for the point on the target's path such that...
t0 = target's original position
w0 = weapon's original position
p = point to fire at
| p - t0 | / | p - w0 | = velocity of target / velocity of projectile
In short, the ratio of the velocities of the two objects must equal the ratio of the distances the projectile and target must travel to meet at the same point.
p in this case is t0 + vt*k, where vt is the velocity of the target and k is the constant you will solve for in the equation.
Hopefully that gets you started. Express the magnitudes above as calculations on the vector components, and it should evaluate to a quadratic that has one, two, or no solutions for k.
[edited by - Waverider on November 4, 2002 4:42:48 PM]
You know that the point you're going to fire at is somewhere along the straight-line trajectory of the target object.
If you know the velocity of your projectile, and the velocity of the target object, then you just solve for the point on the target's path such that...
t0 = target's original position
w0 = weapon's original position
p = point to fire at
| p - t0 | / | p - w0 | = velocity of target / velocity of projectile
In short, the ratio of the velocities of the two objects must equal the ratio of the distances the projectile and target must travel to meet at the same point.
p in this case is t0 + vt*k, where vt is the velocity of the target and k is the constant you will solve for in the equation.
Hopefully that gets you started. Express the magnitudes above as calculations on the vector components, and it should evaluate to a quadratic that has one, two, or no solutions for k.
[edited by - Waverider on November 4, 2002 4:42:48 PM]
It's not what you're taught, it's what you learn.
November 04, 2002 05:01 PM
Well, here is one possiblity. Bear in mind a couple of limitations. First, this doesn''t take into account any initial velocity from cannon. Second, it doesn''t take into account that your universe is quantized in both time and space. Therefore the two objects might never line up precisely because the point or time at which they would have collided is between the quanta.
Also note that I haven''t tested this therefore buyer beware etc.
-D
Also note that I haven''t tested this therefore buyer beware etc.
const double PI = 3.1415;// returns a positive angle in radians. If there is not// possible trajectory, it returns a negative number.double calculateAngle(double bulletSpeed, double xProjectilePos, double yProjectilePos, double xTargetPos, double yTargetPos, double xTargetVel, double yTargetVel){// first calculate time double a = pow(yTargetVel, 2) + pow(xTargetVel, 2) - pow(bulletSpeed, 2); double b = 2 * (yTargetVel * (yTargetPos - yProjectilePos) + xTargetVel * (xTargetPos - xProjectilePos) ); double c = pow(yTargetPos - yProjectilePos, 2) + pow(xTargetPos - xProjectilePos, 2); double d = pow(b, 2) - 4*a*c; if ( d < 0) return -1.0; double time1 = ((-1.0) * b - sqrt(d)) / (2 * a); double time2 = ((-1.0) * b + sqrt(d)) / (2 * a); if (time1 < 0 && time2 < 0) return -1.0; double time; if (time1 < time2) time = time1; else time = time2;// use time to calculate the vector elements of the velocity double xProjectileVel = (xTargetPos + time * xTargetVel - xProjectilePos) / time; double yProjectileVel = (yTargetpos + time * yTargetVel - yProjectilePos) / time; double angle; if (xProjectileVel != 0.0) angle = arctan(yProjectileVel / xProjectileVel); else { if (yProjectileVel >= 0) return PI / 2; else return (3.0 * PI) / 2; }// use the vector elements to calculate the angle// first we need to find the quadrant that the angle is in if (xProjectileVel >= 0 && yProjectileVel >= 0) { // we''re in quadrant 1. This means that we can just // return the value. return angle; } else if (xProjectileVel < 0 && yProjectileVel >= 0) { // we''re in quadrant 2. return PI + angle; } else if (xProjectileVel < 0 && yProjectileVel < 0) { // quadrant 3 return PI + angle; } else { // quadrant 4 return 2*PI + angle; }}
-D
November 04, 2002 05:09 PM
Ack. I noticed a bug.
instead of the lines
Instead substitute
Here is a bit about how I got the equations I did so you can check me. There are three equations and three unknowns:
time * xProjectileVel + xProjectilePos = time * xTargetVel + xTargetPos
time * yProjectileVel + yProjectilePos = time * yTargetVel + yTargetPos
xProjectileVel^2 + yProjectileVel^2 = bulletSpeed^2
The rest is just the result of substitutions and some algebra.
-D
instead of the lines
if (time1 < 0 && time2 < 0) return -1.0;double time;if (time1 < time2) time = time1;else time = time2;
Instead substitute
double time;if (time1 < 0 && time2 < 0) return -1.0;else if (time1 < 0) time = time2;else if (time2 < 0) time = time1;else if (time1 < time2) time = time1;else time = time2;
Here is a bit about how I got the equations I did so you can check me. There are three equations and three unknowns:
time * xProjectileVel + xProjectilePos = time * xTargetVel + xTargetPos
time * yProjectileVel + yProjectilePos = time * yTargetVel + yTargetPos
xProjectileVel^2 + yProjectileVel^2 = bulletSpeed^2
The rest is just the result of substitutions and some algebra.
-D
Thanks guys - I did run into some problems though :
Wave - From my limited knowledge of mathematics, the subtraction of one point from another eg "p - t0", is a vector. I''m not sure what the | | operator does to a vector though, nor how one divides a vector by a vector if the result of the | | operator is a vector itself.
Also, are you suggesting that I substitute t0 + vtarget*k for p, and then algebraically manipulate to get k on one side?
AP - Thanks for all the code, it looks like it might be what I need, but I had a problem where the angle doesn''t seem to be on an intercept heading, but tending more toward the initial position of the target ie lagging behind a lot.
I took the liberty of altering quadrant 2 to return (PI - angle), and quadrant 4 to return (2*PI - angle), although I did also try with the initial expressions.
Can you see anything in your code that might be the cause of the problem?
Wave - From my limited knowledge of mathematics, the subtraction of one point from another eg "p - t0", is a vector. I''m not sure what the | | operator does to a vector though, nor how one divides a vector by a vector if the result of the | | operator is a vector itself.
Also, are you suggesting that I substitute t0 + vtarget*k for p, and then algebraically manipulate to get k on one side?
AP - Thanks for all the code, it looks like it might be what I need, but I had a problem where the angle doesn''t seem to be on an intercept heading, but tending more toward the initial position of the target ie lagging behind a lot.
I took the liberty of altering quadrant 2 to return (PI - angle), and quadrant 4 to return (2*PI - angle), although I did also try with the initial expressions.
Can you see anything in your code that might be the cause of the problem?
| | means take the magnitude of the vector which results in a scalar. I would square both sides of the equation to get rid of the square root portion, though.
And yes, substitute p and get k by itself.
Good luck!
And yes, substitute p and get k by itself.
Good luck!
It's not what you're taught, it's what you learn.
November 05, 2002 01:32 PM
I wrote up a quick an dirty test program for the algorithm. I modified it so that instead of returning an angle it returned the vector in its component parts.
I tested a couple of cases and they were both exactly right. This means that the problem is the code that converts the vector components into an angle.
Here is the function and driver that just returns a vector:
If you still need just the angle, find a trig book and learn more about the arc functions. They have a lot of special cases which is probably where I went astray.
-D
I tested a couple of cases and they were both exactly right. This means that the problem is the code that converts the vector components into an angle.
Here is the function and driver that just returns a vector:
#include <iostream>#include <iomanip>#include <cmath>#include <cstdlib>using namespace std;struct Vec { Vec() : x(0), y(0) {} double x; double y;};Vec calculateAngle(double bulletSpeed, double xProjectilePos, double yProjectilePos, double xTargetPos, double yTargetPos, double xTargetVel, double yTargetVel);const double PI = 3.1415;int main(){ cout << setprecision(4) << setiosflags(ios::fixed | ios::showpoint); double bulletSpeed, xProjectilePos, yProjectilePos, xTargetPos, yTargetPos, xTargetVel, yTargetVel; cout << "\nWhat is the bullet speed?"; cin >> bulletSpeed; cout << "What is the x projectile position?"; cin >> xProjectilePos; cout << "What is the y projectile position?"; cin >> yProjectilePos; cout << "What is the x target position?"; cin >> xTargetPos; cout << "What is the y target position?"; cin >> yTargetPos; cout << "What is the x target velocity?"; cin >> xTargetVel; cout << "What is the y target velocity?"; cin >> yTargetVel; Vec projectileVel = calculateAngle(bulletSpeed, xProjectilePos, yProjectilePos, xTargetPos, yTargetPos, xTargetVel, yTargetVel); for (int i=0; i<100; ++i) { cout << "\nTarget: (" << xTargetPos << " , " << yTargetPos << ")\tProjectile: (" << xProjectilePos << " , " << yProjectilePos << ")"; xProjectilePos += projectileVel.x; yProjectilePos += projectileVel.y; xTargetPos += xTargetVel; yTargetPos += yTargetVel; } cout << endl; system("pause"); return 0;}// returns a positive angle in radians. If there is not// possible trajectory, it returns a negative number.Vec calculateAngle(double bulletSpeed, double xProjectilePos, double yProjectilePos, double xTargetPos, double yTargetPos, double xTargetVel, double yTargetVel){ // first calculate time double a = pow(yTargetVel, 2) + pow(xTargetVel, 2) - pow(bulletSpeed, 2); double b = 2 * (yTargetVel * (yTargetPos - yProjectilePos) + xTargetVel * (xTargetPos - xProjectilePos) ); double c = pow(yTargetPos - yProjectilePos, 2) + pow(xTargetPos - xProjectilePos, 2); double d = pow(b, 2) - 4*a*c; if ( d < 0) return Vec(); double time1 = ((-1.0) * b - sqrt(d)) / (2 * a); double time2 = ((-1.0) * b + sqrt(d)) / (2 * a); double time; if (time1 < 0 && time2 < 0) return Vec(); else if (time1 < 0) time = time2; else if (time2 < 0) time = time1; else if (time1 < time2) time = time1; else time = time2; // use time to calculate the vector elements of the velocity double xProjectileVel = (xTargetPos + time * xTargetVel - xProjectilePos) / time; double yProjectileVel = (yTargetPos + time * yTargetVel - yProjectilePos) / time; cout << "\nTime: " << time << endl << endl;/* double angle; if (xProjectileVel != 0.0) angle = arctan(yProjectileVel / xProjectileVel); else { if (yProjectileVel >= 0) return PI / 2; else return (3.0 * PI) / 2; } // use the vector elements to calculate the angle // first we need to find the quadrant that the angle is in if (xProjectileVel >= 0 && yProjectileVel >= 0) { // we''re in quadrant 1. This means that we can just // return the value. return angle; } else if (xProjectileVel < 0 && yProjectileVel >= 0) { // we''re in quadrant 2. return PI + angle; } else if (xProjectileVel < 0 && yProjectileVel < 0) { // quadrant 3 return PI + angle; } else { // quadrant 4 return 2*PI + angle; }*/ Vec retVal; retVal.x = xProjectileVel; retVal.y = yProjectileVel; return retVal;}
If you still need just the angle, find a trig book and learn more about the arc functions. They have a lot of special cases which is probably where I went astray.
-D
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement