As mentioned at the end of the last post, it is time to add the various lines used in the game of squash. E.G Service and receiving boxes, playing area, etc. These lines are for the most part pretty straightforward—straight line between two points. The exception perhaps is the top of the playing area on the right wall. Still straight lines, but… Another are the service boxes which are circular arcs.

Given our function, it is pretty much a matter of adding more points to our array of court points. Translating to their isometric equivalents. Then plotting those. Expect the only hiccup will be the service “boxes”.

Straight Lines

Okay let’s get the easiest stuff out of the way. I am not going to worry about drawing the lines at the official width. Seems like too much work. Maybe in future. These are the lines we are looking at (see resources for link):

  • top: front wall, 20 feet
  • tin: front wall, 17 inches above the floor
  • service line, front wall 8 feet 2 inches above the floor (bottom of line)
  • top: side wall 20 feet for front 31 feet, 15 feet high for remaining 14 feet
  • return boxes: floor, 15 feet by 12.5 feet at back of court

Let’s update the crt_points array. I am showing the current complete state. And, if I failed to mention it before, we need both ends of any line when plotting it with matplotlib.

crt_points = [[0, 0, 0], [25, 0, 0], [25, 45, 0], [0, 45, 0],
              [25, 0, 0], [25, 0, 24], [25, 45, 24], [25, 45, 0],
              [25, 45, 0], [25, 45, 24], [0, 45, 24], [0, 45, 0],
              [0, 45, 20], [25, 45, 20],
              [0, 45, 8 + 1/6], [25, 45, 8 + 1/6],
              [0, 45, 17/12], [25, 45, 17/12],
              [25, 45, 20], [25, 14, 20], [25, 14, 15], [25, 0, 15],
              [0, 15, 0], [25, 15, 0], [12.5, 15, 0], [12.5, 0, 0]
              ]

The loop to translate the above to the isometric version has not changed. Nor has the code to setup the figure and axes in matplotlib.

But we do need to deal with all the extra plotting. I am going to show the code for all the lines including the floor and ceiling of the court.

# floor
for i in range(4):
  ln_to = (i + 1) % 4
  ax.plot([iso_1[i][0], iso_1[ln_to][0]], [iso_1[i][1], iso_1[ln_to][1]], c='k')

# side wall
for i in range(4, 7):
  ln_to = ((i + 1) % 4) + 4
  ax.plot([iso_1[i][0], iso_1[ln_to][0]], [iso_1[i][1], iso_1[ln_to][1]], c='k')
  # ax.scatter(iso_1[5][0], 0.8165*iso_1[5][1], c='g')

# front wall
for i in range(9,11):
  ln_to = ((i + 1) % 4) + 8
  ax.plot([iso_1[i][0], iso_1[ln_to][0]], [iso_1[i][1], iso_1[ln_to][1]], c='k')

# front wall lines
ax.plot([iso_1[12][0], iso_1[13][0]], [iso_1[12][1], iso_1[13][1]], c='r')
ax.plot([iso_1[14][0], iso_1[15][0]], [iso_1[14][1], iso_1[15][1]], c='r')
ax.plot([iso_1[16][0], iso_1[17][0]], [iso_1[16][1], iso_1[17][1]], c='r')

# side wall top line, it steps down at some point
for i in range(18,21):
  ln_to = i + 1
  ax.plot([iso_1[i][0], iso_1[ln_to][0]], [iso_1[i][1], iso_1[ln_to][1]], c='r')
# tee lines
ax.plot([iso_1[22][0], iso_1[23][0]], [iso_1[22][1], iso_1[23][1]], c='r')
ax.plot([iso_1[24][0], iso_1[25][0]], [iso_1[24][1], iso_1[25][1]], c='r')
isometric view of a hardball doubles court with all but the services boxes shown
Isometric view of a hardball doubles court less the service boxes.

Service Boxes

Well “boxes” is not quite accurate. But in squash singles they are boxes, so that’s what most players call them as they usually start out playing singles a fair while before doubles. Each service box is a 4 feet 6 inch arc from wall to t-line, centred on where the t-line touches the wall.

matplotlib’s patches class provides an Arc method. So, let’s give that a try.

First of all we have to take into consideration that the length of dimensions on the angled elements of the projection get foreshortened. In our case that is by \(\frac{2}{\sqrt{6}}\) which is approximately \(0.8165\). So, when sorting the length of our arcs we will need to reduce that 4 feet 6 inches appropriately. That value will define the diameter of the arc in both directions (width, height). We want a circlar arc so both will be the same.

I believe the parameters of most interest for our case are:

theta1, theta2 : float, optional

Starting and ending angles of the arc in degrees. These values are relative to angle, e.g. if angle = 45 and theta1 = 90 the absolute starting angle is 135. Default theta1 = 0, theta2 = 360, i.e. a complete ellipse. The arc is drawn in the counterclockwise direction. Angles greater than or equal to 360, or smaller than 0, are represented by an equivalent angle in the range [0, 360), by taking the input value mod 360.

Looking at the previous image, I looks pretty clear that the arc will need to cover 60° worth of a full circle. Since the arc is drawn counter-clockwise, the starting point will need to be on the left wall. And assuming that the start of the arc, 0°, is on the x-axis, we will need to start at -30° and finish at 30°. Let’s give that a go.

# service boxes
a_wd = 2 * 4.5 * (2 / math.sqrt(6))
# center of circle for left service box
l_center = (iso_1[22][0], iso_1[22][1])
# center of circle for right service bos
r_center = (iso_1[23][0], iso_1[23][1])
e1 = patches.Arc(l_center, a_wd, a_wd, 0, theta1=-3, theta2=30, color='r')
ax.add_patch(e1)
isometric view of a hardball doubles court with all but the right service box shown
Isometric view of a hardball doubles court less the right service box.

Pretty good guess work!

Now for the left service box. Now since the arc is draw counter clockwise our starting point will need to be on the t-line. Which looks to me to be 30° greater than 180°. And the finishing point, just like the wall on the left, must be at -30°. Let’s give that a go.

e2 = patches.Arc(r_center, a_wd, a_wd, 0, theta1=210, theta2=-30, color='r')
ax.add_patch(e2)
complete isometric view of a hardball doubles court
Isometric view of a hardball doubles court.

Another pretty good guess. And there we are—an isometric view of a hardball doubles squash court. Not bad if I do say so myself.

Done

A short post. I had considered covering the reason, with code and examples, of why I tackled generating this isometric projection. But it is not really related to generating the isometric projection. So didn’t think it belonged in this post; which is rather focused on its subject.

So, another post which will look at high volleys and interference on a doubles squash court.

Until then, do commit to some fun, but educational, time at the keyboard.

Resources