Skip to main content

Overview

Corner data defines the physical geometry of the racetrack, providing coordinates and metadata for each numbered corner. This data is essential for spatial analysis, track visualization, and correlating telemetry position data with specific track locations.
Corner data enables you to map telemetry coordinates to real track features, create accurate track visualizations, and analyze driver performance through specific corners.

File Location

Corner data is stored once per circuit (consistent across sessions at the same track):
Pre-Season Testing 2/Practice 3/corners.json
Example:
  • Pre-Season Testing 2/Practice 3/corners.json
  • Bahrain Grand Prix/Race/corners.json
  • Monaco Grand Prix/Qualifying/corners.json
The same circuit will have identical corner data across all sessions (Practice, Qualifying, Race).

Data Structure

The JSON file contains parallel arrays where each index represents one corner:
{
  "CornerNumber": [1, 2, 3, 4, 5, ...],
  "X": [42.41, 820.78, 1912.97, 7487.75, ...],
  "Y": [8329.20, 7879.04, 8065.44, 6790.71, ...],
  "Angle": [-246.62, -101.18, -261.39, -349.60, ...],
  "Distance": [706.12, 802.13, 909.97, 1487.44, ...],
  "Rotation": 92.0
}

Field Reference

CornerNumber
array<number>
required
Sequential number identifying each corner of the circuit.Range: 1 to number of corners (typically 12-20 corners per circuit)
Example: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
X
array<number>
required
Horizontal X coordinate of the corner on the track map.Unit: meters
Coordinate system: Arbitrary origin, consistent with telemetry position data
Example: [42.41, 820.78, 1912.97, 7487.75, 5820.23, ...]
Y
array<number>
required
Horizontal Y coordinate of the corner on the track map.Unit: meters
Coordinate system: Arbitrary origin, consistent with telemetry position data
Example: [8329.20, 7879.04, 8065.44, 6790.71, 4860.74, ...]
Angle
array<number>
required
Visual offset angle in degrees, used to position corner number markers on track maps in a logical direction (usually orthogonal to the track).Unit: ° (degrees)
Range: -360 to +360
Purpose: Determines where to place corner number labels so they don’t overlap with the track line
Example: [-246.62, -101.18, -261.39, -349.60, -211.50, ...]
This angle is for visualization purposes only—it positions corner labels away from the track line on a map. It does NOT represent the corner’s turning angle or trajectory.
Distance
array<number>
required
Distance from the start/finish line to this corner marker, measured along the racing line.Unit: meters
Example: [706.12, 802.13, 909.97, 1487.44, 1775.40, ...]
This field is crucial for correlating telemetry distance values with corner numbers. For example, if telemetry shows distance = 1500, you’re between corners 3 (910m) and 4 (1487m).
Rotation
number|null
required
Rotation of the entire circuit coordinate system in degrees. Used to align telemetry position data with official track map orientation.Unit: degrees
Value: Single number (applies to entire track) or null if no rotation needed
Example: 92.0 (track is rotated 92° clockwise from north-up orientation)
To match official FIA track maps, apply this rotation to all X, Y coordinates from telemetry and corner data:
X_rotated = X * cos(Rotation) - Y * sin(Rotation)
Y_rotated = X * sin(Rotation) + Y * cos(Rotation)

Real Data Example

Here’s actual corner data from Bahrain International Circuit (Pre-Season Testing 2):
{
  "CornerNumber": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
  "X": [
    42.41,
    820.78,
    1912.97,
    7487.75,
    5820.23,
    5180.40,
    4276.20,
    2490.10,
    2711.16,
    2100.13,
    2120.99,
    4981.25,
    6665.93,
    -145.41,
    -552.81
  ],
  "Y": [
    8329.20,
    7879.04,
    8065.44,
    6790.71,
    4860.74,
    4214.60,
    4156.24,
    2458.60,
    5950.24,
    6614.00,
    -663.995,
    1603.75,
    449.28,
    -3472.81,
    -2803.67
  ],
  "Angle": [
    -246.62,
    -101.18,
    -261.39,
    -349.60,
    -211.50,
    -76.37,
    -258.95,
    -114.65,
    -344.91,
    -270.02,
    -101.00,
    -272.81,
    -358.73,
    -110.52,
    -169.06
  ],
  "Distance": [
    706.12,
    802.13,
    909.97,
    1487.44,
    1775.40,
    1863.11,
    1961.47,
    2213.36,
    2584.71,
    2668.95,
    3446.09,
    3845.83,
    4067.77,
    4865.59,
    4969.25
  ],
  "Rotation": 92.0
}
Circuit Analysis:
  • 15 corners total (typical for Bahrain)
  • Rotation: 92° - Track map needs significant rotation to match north-up orientation
  • Corner 4 (Turn 4) is at distance 1487m - a famous heavy braking zone after the main straight
  • Corner 11 (Turn 11) has negative Y coordinate (-664m) - track extends below the origin point

Use Cases

Track Visualization

Plotting the Circuit
import matplotlib.pyplot as plt
import numpy as np

# Load corner data
corners = load_corners_json()

# Apply rotation if needed
if corners['Rotation']:
    rotation_rad = np.radians(corners['Rotation'])
    cos_r = np.cos(rotation_rad)
    sin_r = np.sin(rotation_rad)
    
    X_rotated = [x * cos_r - y * sin_r for x, y in zip(corners['X'], corners['Y'])]
    Y_rotated = [x * sin_r + y * cos_r for x, y in zip(corners['X'], corners['Y'])]
else:
    X_rotated = corners['X']
    Y_rotated = corners['Y']

# Plot corners
plt.figure(figsize=(12, 8))
plt.scatter(X_rotated, Y_rotated, c='red', s=100, zorder=5)

# Add corner numbers with angle offset for label placement
for i, (x, y, angle, num) in enumerate(zip(X_rotated, Y_rotated, corners['Angle'], corners['CornerNumber'])):
    offset_x = 50 * np.cos(np.radians(angle))
    offset_y = 50 * np.sin(np.radians(angle))
    plt.text(x + offset_x, y + offset_y, f"T{num}", ha='center', va='center')

plt.axis('equal')
plt.title('Circuit Corner Positions')
plt.xlabel('X (meters)')
plt.ylabel('Y (meters)')
plt.show()
Overlay Telemetry on Track Map
# Load telemetry for a lap
telemetry = load_telemetry_json('VER/9_tel.json')

# Plot racing line
plt.plot(telemetry['tel']['x'], telemetry['tel']['y'], 'b-', linewidth=1, alpha=0.5)

# Overlay corners
plt.scatter(corners['X'], corners['Y'], c='red', s=100, zorder=5, label='Corners')

plt.legend()
plt.axis('equal')
plt.title('VER Lap 9 Racing Line with Corners')
plt.show()

Corner Performance Analysis

Identify Corner Entry/Exit Points
import numpy as np

def find_corner_telemetry(telemetry, corner_data, corner_number):
    """
    Extract telemetry data for a specific corner.
    """
    idx = corner_data['CornerNumber'].index(corner_number)
    corner_distance = corner_data['Distance'][idx]
    
    # Find telemetry samples within ±50m of corner
    tel_distances = np.array(telemetry['tel']['distance'])
    mask = np.abs(tel_distances - corner_distance) < 50
    
    return {
        'time': np.array(telemetry['tel']['time'])[mask],
        'speed': np.array(telemetry['tel']['speed'])[mask],
        'throttle': np.array(telemetry['tel']['throttle'])[mask],
        'brake': np.array(telemetry['tel']['brake'])[mask],
        'gear': np.array(telemetry['tel']['gear'])[mask],
        'acc_y': np.array(telemetry['tel']['acc_y'])[mask]
    }

# Compare two drivers through corner 4
ver_corner4 = find_corner_telemetry(ver_telemetry, corners, 4)
sai_corner4 = find_corner_telemetry(sai_telemetry, corners, 4)

plt.plot(ver_corner4['distance'], ver_corner4['speed'], label='VER')
plt.plot(sai_corner4['distance'], sai_corner4['speed'], label='SAI')
plt.xlabel('Distance (m)')
plt.ylabel('Speed (km/h)')
plt.title('Turn 4 Speed Comparison')
plt.legend()
plt.show()
Corner-by-Corner Lap Time Breakdown
def corner_times(telemetry, corner_data):
    """
    Calculate time spent between each pair of corners.
    """
    times = []
    distances = corner_data['Distance']
    
    for i in range(len(distances) - 1):
        start_dist = distances[i]
        end_dist = distances[i + 1]
        
        # Find telemetry indices
        tel_dist = telemetry['tel']['distance']
        tel_time = telemetry['tel']['time']
        
        start_idx = np.argmin(np.abs(np.array(tel_dist) - start_dist))
        end_idx = np.argmin(np.abs(np.array(tel_dist) - end_dist))
        
        sector_time = tel_time[end_idx] - tel_time[start_idx]
        times.append(sector_time)
    
    return times

# Compare corner-by-corner performance
ver_times = corner_times(ver_telemetry, corners)
sai_times = corner_times(sai_telemetry, corners)

delta = [v - s for v, s in zip(ver_times, sai_times)]
corner_labels = [f"T{i}→T{i+1}" for i in range(1, len(delta) + 1)]

plt.bar(corner_labels, delta)
plt.ylabel('Time Delta (s)')
plt.title('VER vs SAI: Corner-by-Corner Delta')
plt.axhline(0, color='black', linewidth=0.5)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

Spatial Queries

Find Closest Corner to Telemetry Position
def closest_corner(x, y, corner_data):
    """
    Find the nearest corner to a given (x, y) position.
    """
    distances = [
        np.sqrt((x - cx)**2 + (y - cy)**2)
        for cx, cy in zip(corner_data['X'], corner_data['Y'])
    ]
    closest_idx = np.argmin(distances)
    return corner_data['CornerNumber'][closest_idx], distances[closest_idx]

# Example: Where was VER at t=45 seconds?
idx = 450  # arbitrary telemetry sample
x = ver_telemetry['tel']['x'][idx]
y = ver_telemetry['tel']['y'][idx]

corner_num, dist = closest_corner(x, y, corners)
print(f"VER was near Turn {corner_num} (within {dist:.1f}m)")

Track Map Rotation

The Rotation field aligns the coordinate system with official track maps:
GPS coordinates and telemetry use an arbitrary coordinate system where:
  • Origin (0, 0) is a reference point near the circuit
  • X and Y axes may not align with north/south
Official FIA track maps are oriented for readability (e.g., main straight horizontal).The Rotation value transforms telemetry coordinates to match official map orientation.

Data Quality Notes

Corner positions are approximate marker locations, not the exact apex coordinates. They represent a reference point near each corner for visualization and analysis purposes.
The Distance field is measured along the racing line, which may differ slightly from the telemetry distance field (measured along the actual car path). Expect small discrepancies (±10-20m) when matching corners to telemetry.

Circuit-Specific Examples

Bahrain International Circuit

  • 15 corners
  • Famous corners: Turn 1 (heavy braking), Turn 4 (long apex), Turn 10 (overtaking zone)
  • Track length: ~5412m (corner 15 distance: 4969m, plus run to finish line)
  • Rotation: 92° (significant rotation needed for north-up maps)

Monaco Street Circuit

  • 19 corners (highest on calendar)
  • Famous corners: Sainte-Devote (T1), Casino Square (T5), Rascasse (T16)
  • Track length: ~3337m (shortest on calendar)
  • Minimal rotation (natural north-south orientation)

Circuit de Spa-Francorchamps

  • 19 corners
  • Famous corners: La Source (T1), Eau Rouge-Raidillon (T3-4), Pouhon (T9)
  • Track length: ~7004m (longest on calendar)
  • Significant elevation (captured in telemetry Z coordinate)
  • Telemetry - 3D position data (x, y, z) and distance values
  • Lap Times - Sector times correlated with corner groups
  • Race Control - Incidents referenced by track sector (correlates with corners)
  • Drivers - Driver information for performance comparison

Build docs developers (and LLMs) love