shoot projectile (straight trajectory) at moving target in 3 dimensions - algorithm

I already googled for the problem but only found either 2D solutions or formulas that didn't work for me (found this formula that looks nice: http://www.ogre3d.org/forums/viewtopic.php?f=10&t=55796 but seems not to be correct).
I have given:
Vec3 cannonPos;
Vec3 targetPos;
Vec3 targetVelocityVec;
float bulletSpeed;
what i'm looking for is time t such that
targetPos+t*targetVelocityVec
is the intersectionpoint where to aim the cannon to and shoot.
I'm looking for a simple, inexpensive formula for t (by simple i just mean not making many unnecessary vectorspace transformations and the like)
thanks!

The real problem is finding out where in space that the bullet can intersect the targets path. The bullet speed is constant, so in a certain amount of time it will travel the same distance regardless of the direction in which we fire it. This means that it's position after time t will always lie on a sphere. Here's an ugly illustration in 2d:
This sphere can be expressed mathematically as:
(x-x_b0)^2 + (y-y_b0)^2 + (z-z_b0)^2 = (bulletSpeed * t)^2 (eq 1)
x_b0, y_b0 and z_b0 denote the position of the cannon. You can find the time t by solving this equation for t using the equation provided in your question:
targetPos+t*targetVelocityVec (eq 2)
(eq 2) is a vector equation and can be decomposed into three separate equations:
x = x_t0 + t * v_x
y = y_t0 + t * v_y
z = z_t0 + t * v_z
These three equations can be inserted into (eq 1):
(x_t0 + t * v_x - x_b0)^2 + (y_t0 + t * v_y - y_b0)^2 + (z_t0 + t * v_z - z_b0)^2 = (bulletSpeed * t)^2
This equation contains only known variables and can be solved for t. By assigning the constant part of the quadratic subexpressions to constants we can simplify the calculation:
c_1 = x_t0 - x_b0
c_2 = y_t0 - y_b0
c_3 = z_t0 - z_b0
(v_b = bulletSpeed)
(t * v_x + c_1)^2 + (t * v_y + c_2)^2 + (t * v_z + c_3)^2 = (v_b * t)^2
Rearrange it as a standard quadratic equation:
(v_x^2+v_y^2+v_z^2-v_b^2)t^2 + 2*(v_x*c_1+v_y*c_2+v_z*c_3)t + (c_1^2+c_2^2+c_3^2) = 0
This is easily solvable using the standard formula. It can result in zero, one or two solutions. Zero solutions (not counting complex solutions) means that there's no possible way for the bullet to reach the target. One solution will probably happen very rarely, when the target trajectory intersects with the very edge of the sphere. Two solutions will be the most common scenario. A negative solution means that you can't hit the target, since you would need to fire the bullet into the past. These are all conditions you'll have to check for.
When you've solved the equation you can find the position of t by putting it back into (eq 2). In pseudo code:
# setup all needed variables
c_1 = x_t0 - x_b0
c_2 = y_t0 - y_b0
c_3 = z_t0 - z_b0
v_b = bulletSpeed
# ... and so on
a = v_x^2+v_y^2+v_z^2-v_b^2
b = 2*(v_x*c_1+v_y*c_2+v_z*c_3)
c = c_1^2+c_2^2+c_3^2
if b^2 < 4*a*c:
# no real solutions
raise error
p = -b/(2*a)
q = sqrt(b^2 - 4*a*c)/(2*a)
t1 = p-q
t2 = p+q
if t1 < 0 and t2 < 0:
# no positive solutions, all possible trajectories are in the past
raise error
# we want to hit it at the earliest possible time
if t1 > t2: t = t2
else: t = t1
# calculate point of collision
x = x_t0 + t * v_x
y = y_t0 + t * v_y
z = z_t0 + t * v_z

Related

Writing a vector sum in MATLAB

Suppose I have a function phi(x1,x2)=k1*x1+k2*x2 which I have evaluated over a grid where the grid is a square having boundaries at -100 and 100 in both x1 and x2 axis with some step size say h=0.1. Now I want to calculate this sum over the grid with which I'm struggling:
What I was trying :
clear all
close all
clc
D=1; h=0.1;
D1 = -100;
D2 = 100;
X = D1 : h : D2;
Y = D1 : h : D2;
[x1, x2] = meshgrid(X, Y);
k1=2;k2=2;
phi = k1.*x1 + k2.*x2;
figure(1)
surf(X,Y,phi)
m1=-500:500;
m2=-500:500;
[M1,M2,X1,X2]=ndgrid(m1,m2,X,Y)
sys=#(m1,m2,X,Y) (k1*h*m1+k2*h*m2).*exp((-([X Y]-h*[m1 m2]).^2)./(h^2*D))
sum1=sum(sys(M1,M2,X1,X2))
Matlab says error in ndgrid, any idea how I should code this?
MATLAB shows:
Error using repmat
Requested 10001x1001x2001x2001 (298649.5GB) array exceeds maximum array size preference. Creation of arrays greater
than this limit may take a long time and cause MATLAB to become unresponsive. See array size limit or preference
panel for more information.
Error in ndgrid (line 72)
varargout{i} = repmat(x,s);
Error in new_try1 (line 16)
[M1,M2,X1,X2]=ndgrid(m1,m2,X,Y)
Judging by your comments and your code, it appears as though you don't fully understand what the equation is asking you to compute.
To obtain the value M(x1,x2) at some given (x1,x2), you have to compute that sum over Z2. Of course, using a numerical toolbox such as MATLAB, you could only ever hope to compute over some finite range of Z2. In this case, since (x1,x2) covers the range [-100,100] x [-100,100], and h=0.1, it follows that mh covers the range [-1000, 1000] x [-1000, 1000]. Example: m = (-1000, -1000) gives you mh = (-100, -100), which is the bottom-left corner of your domain. So really, phi(mh) is just phi(x1,x2) evaluated on all of your discretised points.
As an aside, since you need to compute |x-hm|^2, you can treat x = x1 + i x2 as a complex number to make use of MATLAB's abs function. If you were strictly working with vectors, you would have to use norm, which is OK too, but a bit more verbose. Thus, for some given x=(x10, x20), you would compute x-hm over the entire discretised plane as (x10 - x1) + i (x20 - x2).
Finally, you can compute 1 term of M at a time:
D=1; h=0.1;
D1 = -100;
D2 = 100;
X = (D1 : h : D2); % X is in rows (dim 2)
Y = (D1 : h : D2)'; % Y is in columns (dim 1)
k1=2;k2=2;
phi = k1*X + k2*Y;
M = zeros(length(Y), length(X));
for j = 1:length(X)
for i = 1:length(Y)
% treat (x - hm) as a complex number
x_hm = (X(j)-X) + 1i*(Y(i)-Y); % this computes x-hm for all m
M(i,j) = 1/(pi*D) * sum(sum(phi .* exp(-abs(x_hm).^2/(h^2*D)), 1), 2);
end
end
By the way, this computation takes quite a long time. You can consider either increasing h, reducing D1 and D2, or changing all three of them.

Formula for calculating distance with decaying velocity

I have a moving graphic whose velocity decays geometrically every frame. I want to find the initial velocity that will make the graphic travel a desired distance in a given number of frames.
Using these variables:
v initial velocity
r rate
d distance
I can come up with d = v * (r0 + r1 + r2 + ...)
So if I want to find the v to travel 200 pixels in 3 frames with a decay rate of 90%, I would adapt to:
d = 200
r = .9
v = d / (r0 + r1 + r2)
That doesn't translate well to code, since I have to edit the expression if the number of frames changes. The only solution I can think of is this (in no specific language):
r = .9
numFrames = 3
d = 200
sum = 1
for (i = 1; i < numFrames; i++) {
sum = sum + power(r, i);
}
v = d / sum;
Is there a better way to do this without using a loop?
(I wouldn't be surprised if there is a mistake in there somewhere... today is just one of those days..)
What you have here is a geometric sequence. See the link:
http://www.mathsisfun.com/algebra/sequences-sums-geometric.html
To find the sum of a geometric sequence, you use this formula:
sum = a * ((1 - r^n) / (1 - r))
Since you are looking for a, the initial velocity, move the terms around:
a = sum * ((1-r) / (1 - r^n))
In Java:
int distanceInPixels = SOME_INTEGER;
int decayRate = SOME_DECIMAl;
int numberOfFrames = SOME_INTEGER;
int initialVelocity; //this is what we need to find
initialVelocity = distanceinPixel * ((1-decayRate) / (1-Math.pow(decayRate, NumberOfFrames)));
Using this formula you can get any one of the four variables if you know the values of the other three. Enjoy!
According to http://mikestoolbox.com/powersum.html, you should be able to reduce your for loop to:
F(x) = (x^n - 1)/(x-1)

Verifying properties using Solver

I have a system of equations of the form:
x1 * x2 *.... * xn = a, where * can either be + or - .
I am building some other equation of the same form, and I want to verify
if they are satisfied by the first system.
My question is: Is there a solver that can affirm whether the given equation is satisfied or not?
Many thanks,
Cheers
This is a variation of partition problem with a bias (you need to end up one subset larger than the other by a, instead of them being equal). It can be addressed by adding a to the set, and now solve "regular" partition problem.
This problem is NP-Complete, but can be solved in pseudo-polynomial time using dynamic programming:
D(x,i) = false x<0
D(0,i) = true
D(x,0) = false x != 0
D(x,i) = D(x,i-1) OR D(x-arr[i],i-1)
And you are looking for a subset of sum (x1 + x2 + ... + xn + a) / 2
The idea is to get 2 sets, one with a (let it be A) and one without it (let it be B).
Give all the elements (except a) in A - sign, and all elements in B a + sign.
Since sum(A) = sum(B), you get
sum(B)-(sum(A)-a) = sum(B) - sum(A) + a = 0 + a = a

Implementing semi-implicit backward Euler in a 1-DOF mass-spring system

I have a simple (mass)-spring system wih two points which are connected with a spring. One point is fixed at a ceiling, so I want to calculate the position of the second point using a numerical method. So, basically I get the position of the second point and it's velocity, and want to know how these two value update after one timestep.
The following forces take effect on the point:
Gravitational force, given by -g * m
Spring force, given by k * (l - L) with k being the stiffness, l being the current length and L being the initial length
Damping force, given by -d * v
Summed up, this leads to
F = -g * m + k * (l - L)
Fd = -d * v
Applying for example Explicit Euler, one can derive the following:
newPos = oldPos + dt * oldVelocity
newVelocity = oldVelocity + dt * (F + Fd) / m, using F = m * a.
However, I now want to use semi-implicit backward Euler, but can't exactly figure out where to derive the Jacobians from etc.
So it's probably easiest to see how this goes from considering the fully implicit method first, then going to the semi-implicit.
Implicit Euler would have (let's call these eqn (1)):
newPos = oldPos + dt * newVelocity
newVelocity = oldVelocity + dt * (-g * m + k*(newPos - L) - d*newVelocity)/m
For now let's just measure positions relative to L so we can get rid of that -kL term. Rearranging we end up with
(newPos, newVelocity) - dt * (newVelocity, k/m newPos - d/m newVelocity) = (oldPos, oldVelocity - g*dt)
and putting that into matrix form
((1,-dt),(k/m, 1 - d/m)).(newPos, newVelocity) = (oldPos, oldVelocity -g*dt)
Where you know everything in the matrix, and everything on the RHS, and you just need to solve for the vector (newPos, newVelocity). You can do this with any Ax=b solver (gaussian elimination by hand works in this simple case). But since you mention Jacobians, you're presumably looking to solve this with Newton-Raphson iteration or something similar.
In that case, you're essentially looking to solve the zeros of the equation
((1,-dt),(k/m, 1-d/m)).(newPos, newVelocity) - (oldPos, oldVelocity -g*dt) = 0
which is to say, f(newPos, newVelocity) = (0,0). You have a previous value to use as a starting guess, (oldPos, oldVelocity). Now you just want to iterate on
(x,v)n+1 = (x,v)n + f((x,v)n)/f'((x,v)n)
until you get a sufficiently good answer. Here,
f(newPos,newVel) = ((1,-dt),(k/m, 1-d/m)).(newPos, newVelocity) - (oldPos, oldVelocity -g*dt)
and f'(newPos, newVel) is the Jacobian corresponding the matrix
((1,-dt),(k/m, 1-d/m))
Going through the process for semi-implicit is the same, but a little easier - not all of the RHS terms in eqns (1) are new quantities. The way it's usually done is
newPos = oldPos + dt * newVelocity
newVelocity = oldVelocity + dt * (-g * m + k*oldPos - d*newVelocity)/m
eg, the velocity depends on the old time value of the position, and the position on the new time value of the velocity. (This is very similar to "leapfrog" integration..) You should be able to work through the above steps pretty easilly with this slightly different set of equations. Basically, the k/m term in the matrix above drops away.

Possible ways to calculate X = A - inv(B) * Y * inv(B) and X = Y + A' * inv(B) * A

I have two problems. I have to calculate two equations:
X = A - inv(B) * Y * inv(B)
and
X = Y + A' * inv(B) * A
where, A, B and Y are known p*p matrices (p can be small or large, depends the situation). Matrices are quite dense, without any structure (except B being non-singular of course).
Is it possible to solve X in those equations without inverting the matrix B? I have to calculate these equations n times, n being hundreds or thousands, and all the matrices change over time.
Thank you very much.
If you can express your updates to your matrix B in the following terms:
Bnew = B + u*s*v
then you can express an update to inv(B) explicitly using the Sherman-Morrison-Woodbury formula:
inv(B + u*s*v) = inv(B) - inv(B)*u*inv(s + v*inv(B)*u)*v*inv(B)
If u and v are vectors (column and row, respectively) and s is scalar, then this expression simplifies:
inv(B + u*s*v) = inv(B) - inv(B)*u*v*inv(B)/(s + v*inv(B)*u)
You would only have to calculate inv(B) once and then update it when it changes with no additional inversions.
It may be preferable not to calculate the full inverse, just simple "matrix divisions" on y and (ynew - y) or a and (anew - a) depending on the size of "n" with respect to "p" in your problem.
Memo-ize inv(B), i.e. only invert B when it changes, and keep the inverse around.
If changes to B are small, possibly you could use a delta-approximation.

Resources