Interception of a linear trajectory with constant speed

Today I have been asked about a very common interception problem, which was originally about pirates, but let us wrap it into a different story :

Alice just spotted a white rabbit urging to its rabbit hole ! Given the coordinates of the positions A , B, H of Alice, the bunny and the hole, as well as the respective speeds S_a and S_b of Alice and the rabbit, say whether Alice can catch the Rabbit before it disappears, and give the time and place of the fastest possible interception !

I guess that I am not the first one to solve this problem. However I couldn’t find any simple solution on the internet. So here is one, proving how helpful trigonometry can be when it comes to catching rabbits. The nice thing about it is that, while it relies on trigonometry, it doesn’t actually require to compute any trigonometrical function !

First it is obvious that, since we are looking for the fastest catch, Alice’s trajectory is a straight line. Let us call C and t_C the location and the time of the catch. We have then BC = S_b t_C and AC = S_a t_C. In our problem, finding the length BC would tell us whether Alice can catch the rabbit before is reaches the rabbit hole (case BC < BH), and would immediately lead to both the location and time of the interception :

C = B + \dfrac{BC}{BH}\overrightarrow{BH}

t_C = BC/S_b

To express BC using the coordinates of the points, let us apply the famous Law of Sines to the triangle ABC :

\dfrac{\sin \alpha}{BC} = \dfrac{\sin \beta}{AC} = \dfrac{\sin \gamma}{AB}

Wich leads to

BC = \dfrac {\sin \alpha}{\sin \gamma} AB = \dfrac {\sin \alpha}{\sin \gamma} \sqrt{(x_B-x_A)^2+(y_B-y_A)^2}

Now all we have to do is to express \sin \alpha and \sin \gamma in function of the given data. To do so we will first compute \sin \beta, then we will express \sin \alpha with \sin \beta, and finally \sin \gamma using the two first sines. The value of \sin \beta can be computed from the points coordinates as follows:

\sin \beta = \dfrac{det(\overrightarrow{BA},\overrightarrow{BH})}{ BA * BH } = \dfrac{(x_A - x_B)(y_H-y_B) - (y_A - y_B)(x_H-x_B)}{\sqrt{(x_B-x_A)^2+(y_B-y_A)^2} \sqrt{(x_B-x_H)^2+(y_B-y_H)^2}}

Then we use the Law of Sines again, to compute \sin \alpha :

\sin \alpha = \dfrac{BC}{AC} \sin \beta = \dfrac{S_b t_C}{S_a t_C} \sin \beta = \dfrac{S_b}{S_a} \sin \beta

This only makes sense, of course, if \frac{S_a}{S_b} | \sin \beta | \leq 1. If this is not the case we can deduce that Alice will never catch the rabbit, which solves the problem.
Finally we use the fact that the angles of a triangle sum to \pi to compute \sin \gamma:

\sin \gamma = \sin (\pi - \alpha - \beta) = \sin (\alpha + \beta) = \sin \alpha \cos \beta + \cos \alpha \sin \beta

\sin \gamma = \sin \alpha \sqrt{1 - \sin^2 \beta} + \sin \beta \sqrt{1 - \sin^2 \alpha}

Here we are ! Below is a script implementing this technique using Python's pylab module (but any other langage would do !).


from pylab import *

def interception(A, B, H, Sa, Sb):
	''' Returns None if A cannot catch B before B reaches H.
		Otherwise it returns the time and position of the interception.
		See attached documentation for justifications. '''
	
	sin_beta = det(array((A-B,H-B))) / ( norm(A-B) * norm(H-B) )
	
	sin_alpha = (Sb / Sa) * sin_beta
	
	if abs(sin_alpha) > 1 :
		
		print "B moves too fast to be ever caught !"
		return None
	
	else:
		
		sin_gamma = ( sin_alpha * sqrt(1 - sin_beta**2)
					+ sin_beta * sqrt(1 - sin_alpha**2) )
		
		BC = norm(B-A) * (sin_alpha / sin_gamma) 
		
		if BC > norm(H-A):
		
			print "B reaches H before being caught by A !"
			return None
		
		else:
			
			t = BC / Sb
			C = B + BC * (H-B)/norm(H-B)
	
	print "A intercepted B !"
	return t,C



##### EXAMPLE

# Define the constants

A = array(( 1.0 , 5.0 ))
B = array(( 4.0 , 1.0 ))
H =  array(( 6.0 , 7.0 ))
Sa = 1.1
Sb = 1.0 

# Find the intersection

t,C = interception(A, B, H, Sa, Sb)

# Plot the results

scatter(*zip(A,B,H,C), s=100, color='r')

for label, point in zip(['A','B','H','C'], [A,B,H,C]):
    annotate( label, xy = point, xytext = (-10, 10),
        textcoords = 'offset points', fontsize = 24)
        
annotate("", xy=H, xytext=B, xycoords='data', textcoords='data',size=20,
         arrowprops=dict(arrowstyle="simple",connectionstyle="arc3"))

annotate("", xy=C, xytext=A, xycoords='data', textcoords='data',size=20,
         arrowprops=dict(arrowstyle="simple",connectionstyle="arc3"))

title("A intercepts B in C", fontsize = 24)

show()

And here is the result :