Billiards on Rectangular Tables

Comp 110 Course Module 9a

In this module, we will consider the problem of a ball moving on a horizontal table without friction.  If there are walls along the edges of the table, the ball will rebound when it strikes a wall. Our goal is to calculate the motion of the ball and attempt to understand some of the properties of the ball's trajectory when the ball is given some initial position and velocity.  What we will find is that under certain conditions the ball exhibits what is known as chaotic motion.  The exact definition of chaos is actually rather elusive, although we all probably have some intuitive feeling for what chaotic motion is.  Consider, for example, the motion of a pendulum.  Under small displacements the pendulum has periodic behavior;  the pendulum oscillates back and forth.  This regularity of motion is typical of non-chaotic motion but not of chaotic motion.  In chaotic motion the trajectory is very sensitive to initial conditions;  the trajectory can change dramatically, even for very small changes in the initial conditions.  We will use this rather loose definition of chaotic motion to explore how the motion of a billiard ball can become chaotic under certain conditions.
The basic approach to assembling a model of this kind is to start by building the component pieces and then add new pieces as we add new features.  In this module, we will start by building a function that describes the simple two-dimensional motion of a ball and then add components that simulate the effects of a wall.  If we are careful, we can reuse pieces as the model becomes more complex.  This way we can construct rather complex models that can be easily debugged and reused.

Motion of the ball in the absence of walls

Except for collisions of the ball with a wall, the motion of the ball is actually very simple.   We will define the position of the ball as a function of iteration (i) to be {x[i],y[i]}. Similarly, the x and y components of velocity of the ball is a vector of the form {u[i],v[i]}. (It turns out to be more convenient to express the variables (x,y,u,v) as functions of an integer i rather than functions of a real number t due to the finite precision of storing and retrieving real numbers in Mathematica.) Away from the walls, the position and velocity of the ball are related by the equation

u[i]=x'[i],
v[i]=y'[i].

where the prime (') represents the derivative with respect to time.  Given an initial position {x[0],y[0]} and an initial velocity {u[0],v[0]}, we can solve for the position of the ball at an arbitrary time via the difference equation

x[i+1]=x[i]+dt*u[i],
y[i+1]=y[i]+dt*v[i].

where dt is some predefined timestep and the total time elapsed is simply i × dt.  Note that if we assume that the friction between the ball and the table is negligible, then the velocity of the ball is a constant.  In particular, the velocity is updated via the equations

u[i+1]=u[i],
v[i+1]=v[i].

Given an initial position {x[0],y[0]} and an initial velocity {u[0],v[0]}, we can simulate equations (2) and (3) using a Do loop.  The function trajectory below performs this simulation.

trajectory[{x0_,y0_},{u0_,v0_},dt_,n_]:=Module[{},
Clear[x,y,u,v];
x[0]=x0;
y[0]=y0;
u[0]=u0;
v[0]=v0;
Do[
x[i+1]=x[i]+dt*u[i];
y[i+1]=y[i]+dt*v[i];
u[i+1]=u[i];
v[i+1]=v[i],
{i,0,n-1}]]

Note that rather than returning an answer, trajectory stores the path and velocity in the global variables x,y,u,v.  Before proceeding to add walls to our simulation, we first construct some helper functions for visualization.

Motion of the ball when it strikes a wall

Billiard balls moving in infinite straight lines are not particularly interesting.  To spice things up, we consider next the behavior of the ball when it strikes a wall.  If we assume that the collision is elastic, then the ball will reflect off of the wall with a new velocity that depends both on the old velocity and on the orientation of the wall.  We can capture the orientation of the wall in terms of the unit vector normal to the wall.  This vector is the unique vector n of unit magnitude (i.e., |n|=1) that is perpendicular to the wall and oriented towards the exterior of the billiard table.

Given the old velocity vector p and the unit normal vector n, we can compute the new velocity vector by expressing the old velocity p in terms the component of the velocity (Subscript[p, n]) normal (i.e. perpendicular) to the wall and the component of the velocity (Subscript[p, p]) parallel to the wall; i.e.

p=(Subscript[p, p])+(Subscript[p, n])

The component (Subscript[p, n]) is simply the projection of p on the unit normal vector n.  Thus the length of (Subscript[p, n]) is the dot product of the unit normal n with the velocity vector p.  Therefore,

(Subscript[p, n])=(n.p)n

The velocity (Subscript[p, p]) parallel to the wall is p-(Subscript[p, n]) or equivalently

(Subscript[p, p])=p-(n.p)n.

To compute the new velocity after collision with the wall, note that the normal component (Subscript[p, n]) of the ball's velocity reverses sign upon striking the wall while the parallel component (Subscript[p, p]) of the ball's velocity remains unchanged.  Therefore, the new reflected velocity vector r has the form

({{r, =, (Subscript[p, p])-(Subscript[p, n]),}, { , =, p-(n.p)n-(n.p)n,}, { , =, p-2(n.p)n.}})

Motion on closed tables

The motion of the ball on a closed billiard table can be determined by the following algorithm:

1. Update the position of the ball using equation (2).

2. Test to see if the new position is inside or outside of the table, and update the velocity of the ball.

a. If the ball is inside the table, then keep the old velocity of the ball.

b. If the ball is outside the table (or at a wall), then compute the normal to the boundary (wall) and update the velocity by reflecting the old velocity with respect to the normal.

Our goal in the exercises below is to implement a modified version of the function trajectory.  To modify trajectory, we need two new functions that take into account the geometry of the billiard table.  These functions are:

insideQ[{x,y}] -- tests whether a point is inside of the table or not and returns either True or False.

normal[{x,y}] --  returns the normal to the wall at the point {x,y}, which will be used in the function reflect[n,p].