| 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 Requirements
Windows 95/98/2000
Delphi 3/4/5 (to recompile)
Basketball.EXEHardware Requirements
VGA display monitor
Procedure
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
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)
x real world coordinate (increasing left-to-right)
j integer pixel coordinate (increasing top-to-bottom)
y real world coordinate (increasing bottom-to-top)

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; TRealPoint =
RECORD
x: TReal;
y: TReal
END;
TRealRect =
RECORD
CASE Integer OF
0: (Left, Top, Right, Bottom: TReal);
1: (TopLeft, BottomRight: TRealPoint)
END;
TSimplePantograph =
CLASS(TObject)
PRIVATE
FCanvas : TCanvas;
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
Copyright 2001 efg
Updated
22 Jun 2007
since
18 Feb 2001