Basketball Court | Lab Report |

**Purpose
**The purpose of this project is to show how to map real-world
coordinates to pixel coordinates. In addition, this particular example
shows how to draw a diagram of a basketball court and how to determine if a given point
on the court would be a 2-point or 3-point shot against a specified goal.

**Materials and Equipment**

Software RequirementsWindows 95/98/2000

Delphi 3/4/5 (to recompile)

Basketball.EXE

Hardware RequirementsVGA display monitor

**Procedure**

- From Windows Explorer, double-click on the
*Basketball.Exe*icon to start the program. - With the
*ComboBox*at the upper-left of the screen, choose between "High School / College" and "NBA". - With the default "Time Out"
*ComboBox*selected at the upper-right of the screen, move the cursor around the image to see both the (x, y) coordinates in feet and the (i, j) pixel coordinates. - From the
*ComboBox*selected at the upper-right, select "Shoot on Left Goal" or "Shoot on Right Goal". Move the cursor around the image to see one of these two messages:

Consult various web sites, such as the following, to see maps and specifications of basketball courts:

- Out of bounds
- Distance to goal xx.x feet -> {TWO | THREE} points

- www.sports4kids.com/baskethoop.htm
- www.handymanwire.com/articles/basketballcourt.html
- www.maplefloor.org/literature/gamemarkings/nbabasket.htm (NBA)

A college or high school court is 84 feet long by 50 feet wide. An NBA court is 94 feet long by 50 feet wide. So let's define "world coordinates" for this problem to be an area with coordinates from -50 to +50 feet from left-to-right, and from -30 to +30 feet from bottom to top. These world coordinates will have an origin an the center of the basketball court, and will have the "normal" quadrants from mathematics.

Before introducing the *TSimplePantograph* class, let's review the
mathematics needed for this mapping of (x, y) real coordinates to (i, j) pixel
coordinates.

Given:

*
i* integer pixel coordinate (increasing left-to-right)

** j** integer pixel coordinate (increasing top-to-bottom)

These ratios are maintained:

(x - xMin) / (xMax - xMin) = (i - iMin) / (iMax - iMin)

(y - yMax) / (yMin - yMax) = (j - jMin) / (jMax - jMin)

Rearrangement of these ratios yield the following expressions:

**Map (i, j) Pixel Coordinates to (x,y) World Coordinates**

x = xMin + (xMax - xMin)(i - iMin) / (iMax - iMin)

y = yMax + (yMin - yMax)(j - jMin) / (jMax - jMin)

By inspection:

(iMin, jMin) maps to (xMin, yMax)

(iMax, jMax) maps to (xMax, yMin)

**Map (x,y) World Coordinates to (i, j) Pixel Coordinates
**i = iMin + (iMax - iMin)(x - xMin) / (xMax - xMin)

j = jMin + (jMax - jMin)(y - yMax) / (yMin - yMax)

All of the above equations simplify somewhat when iMin=0 or jMin=0, which is often the case.

The *TSimplePantograph *class is used to make the mapping to/from the
real world and pixel coordinates.

MapWorldToPixel.Pas |

// Define "Real" analogs to TPoint and TRect TYPE TReal = Double;
FPixelRect: TRect; FRealRect : TRealRect; FxDelta : TReal; FyDelta : TReal; FiDelta : INTEGER; FjDelta : INTEGER; FiDeltaOverxDelta: TReal; FjDeltaOveryDelta: TReal; FxDeltaOveriDelta: TReal; FyDeltaOverjDelta: TReal; PUBLIC CONSTRUCTOR Create(Canvas: TCanvas; PixelRect: TRect; RealRect: TRealRect); // Could make these functions but don't always want to use .x and .y // to access fields. PROCEDURE MapRealToPixel(CONST x,y: TReal; VAR i,j: INTEGER); PROCEDURE MapPixelToReal(CONST i,j: INTEGER; VAR x,y: TReal); PROCEDURE MoveTo(CONST x,y: TReal); PROCEDURE LineTo(CONST x,y: TReal); PROCEDURE Ellipse(CONST x1,y1, x2,y2: TReal); PROCEDURE Arc(CONST x1,y1, x2,y2, x3,y3, x4,y4: TReal); PROPERTY Canvas: TCanvas READ FCanvas; END; FUNCTION RealPoint(CONST aX, aY: DOUBLE): TRealPoint; FUNCTION RealRect(CONST aLeft, aTop, aRight, aBottom: DOUBLE): TRealRect; |

The *SimplePantograph *constructor connects a specified canvas with the
two rectangular areas: the array of pixels, and the world coordinates that
define the basketball court..

ScreenBasketball.PAS |

... Bitmap.Width := ImageCourt.Width; Bitmap.Height := ImageCourt.Height; Bitmap.PixelFormat := pf24bit; ... // Origin of area is the center of the basketball court. "Normal" // math quadrants are used ("y" dimension is flipped). Pantograph := TSimplePantograph.Create( Bitmap.Canvas, Rect(0,0,Bitmap.Width,Bitmap.Height), RealRect(-50,30, 50,-30 {ft}) ); ... |

Drawing the basketball court was broken into several local routines in the *DrawCourt
*method in the *ScreenBasketball *unit:

DrawOutline; DrawCenterCourt; DrawHashLines; ... DrawFoulLanes; ... DrawThreePointLines; |

Instead of using the MoveTo/LineTo Canvas methods that operate with pixel
coordinates, similar methods of the *TSimplePantograph* can be used to draw
directly in "world coordinates." For example, DrawOutline shows
the outline of the basketball court:

PROCEDURE DrawOutline; BEGIN // Outline of court Pantograph.MoveTo(-HalfLength, HalfWidth); Pantograph.LineTo( HalfLength, HalfWidth); Pantograph.LineTo( HalfLength,-HalfWidth); Pantograph.LineTo(-HalfLength,-HalfWidth); Pantograph.LineTo(-HalfLength, HalfWidth); // Save this rect to determine if shot is "in bounds" RectCourt := RealRect(-HalfLength,HalfWidth, HalfLength,-HalfWidth); END {DrawOutline}; |

The most difficult part of the court to draw is the 3-point line, especially in a way that can be used to draw both the college court and the NBA court. In both cases, the 3-point line is an arc of a circle with a specified radius. This arc intersects two lines that are parallel to the sides of the court. These lines parallel to the sides of the court are also at a specified location and length. The following shows how draw the 3-point line around the "right" goal in the diagram. Similar code is used to draw the line for the "left" goal.

PROCEDURE DrawThreePointLines; VAR xCenter: Double; yCenter: Double; BEGIN // Three Point Line: Right side xCenter := BaselineRight - BackboardToBaseLine - GoalCentertoBackBoard; yCenter := 0.0; GoalRight := RealPoint(xCenter, yCenter); Pantograph.Arc(xCenter-ThreePointRadius, yCenter+ThreePointRadius, xCenter+ThreePointRadius, yCenter-ThreePointRadius, BaselineRight - ThreePointStraight, ThreePointSide, BaselineRight - ThreePointStraight, -ThreePointSide); Pantograph.MoveTo(BaselineRight, ThreePointSide); Pantograph.LineTo(BaselineRight - ThreePointStraight, ThreePointSide); Pantograph.MoveTo(BaselineRight, -ThreePointSide); Pantograph.LineTo(BaselineRight - ThreePointStraight, -ThreePointSide); // Save RectRight for 2/3-point determination RectRight := RealRect(BaselineRight - ThreePointStraight, ThreePointSide, BaselineRight, -ThreePointSide); ... |

The (xCenter, yCenter) point above is the center of the basket rim projected onto the floor.

The *ImageCourtMouseMove* method is called to display various data in
the *TLabel *at the lower left of the screen. As shown below, the *Pantograph.MapPixelToReal
*method maps the pixel (X, Y) to world coordinates (xFeet, yFeet). [I
usually use (I, J) for a pixel coordinate but here I must deal with Delphi's
convention in the automatic definition of this function's header.] The
case "0" of the CombBoxShot is for the "Time Out"
state. This default state simply shows both sets of coordinates.

procedure TFormBasketballCourt.ImageCourtMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); VAR Distance: Double; xFeet : Double; yFeet : Double; s : STRING; FUNCTION InRealRect(CONST RealRect: TRealRect; CONST X, Y: Double): BOOLEAN; BEGIN RESULT := (X >= RealRect.Left) AND (X <= RealRect.Right) AND (Y <= RealRect.Top) AND (Y >= RealRect.Bottom) END {InRealrect}; begin Pantograph.MapPixelToReal(X,Y, xFeet,yFeet); s := ''; Case ComboBoxShot.ItemIndex OF 0: BEGIN // "Time out" s := 'Pixel(' + IntToStr(X) + ', ' + IntToStr(Y) + ') Feet(' + Format('%.1f, %.1f)', [xFeet, yFeet]); END; 1: BEGIN // Shot on left goal IF InRealRect(RectCourt, xFeet,yFeet) THEN BEGIN Distance := SQRT( SQR(xFeet-GoalLeft.X) + SQR(yFeet-GoalLeft.Y) ); s := Format('Distance to goal %.1f feet', [Distance]); IF InRealRect(RectLeft, xFeet,yFeet) OR // Inside rectangle ((xFeet > RectLeft.Right) AND (Distance < ThreePointRadius) ) // Inside arc THEN s := s + ' -> TWO points' ELSE s := s + ' -> THREE points' END ELSE s := 'Out of bounds' END; ... |

Case "1" above shows the logic for the "Shoot on Left
Goal" ComboBox selection. The first check is to see if the point is
within the *RealRect* that defines the outline of the basketball
court. If the point is outside the court, "Out of bounds" is
displayed. For an "in bounds" location, the next IF statement
determines whether a shot scores two or three points.

If you study the floor diagram, the union of two areas define where two points are scored. The remaining areas are where three points are scored. The two-point area is the union of a rectangle and a "slice" of a circle.

The rectangle is defined by the lines parallel to the sides of the
court. The *InRealRect* function above determines if a mouse location
is in this area. In addition to this rectangular area, the sector check is
a bit more complicated. A simple distance calculation from the point to
the basket is nearly enough but this location must be the right of the rectangle
discussed above.

**Conclusions
**The basketball court example shows how to map "world
coordinates" to pixel coordinates to draw a basketball court familiar to
many. Many times working with "world coordinates" makes solving
a graphics problem much easier than always working directly with pixel
coordinates.

[A 3D version of the basketball court may be the topic of a future project when I update the existing football field project.]

**Keywords: **

TSimplePantograph, world coordinates, TRect, TRealRect, TPoint,
TRealPoint, Point in Rectangle, arc, ellipse, Windows
95/98/2000, Delphi 3/4/5

**Download
**Delphi 3/4/5 Source and EXE (175 KB): Basketball.ZIP

Updated | 13 Jun 2009 |

Since | 18 Feb 2001 |