Procedural race track generation with Python.
Blog post with more insights here.
Following the article found here.
The tracks obtained by my implementation are far from ideal, but it might be a good starting point for further work.
As explained in the post mentioned above, which I strongly recommend you to read, below you can find the steps taken to generate a track. Note that there are some restrictions and parameters used in the code which are not explained in the summary presented below. You can dive in the code to learn more about them.
The outline of the algorithm is:
- Generate a set of random points (white points)
- Compute the points that, from the set of all points generated in step 1, form the convex Hull (red lines)
- For each pair of consecutive points in the convex hull, compute the midpoint and displace it by a random bounded amount
- Push points whose distance is less than a predefined threshold apart an limit the max angle between them.
- From the final set of points, compute a spline that passess through all of them.
By following this steps we can get the layout of the track.
Once the layout has been obtained we can draw the racetrack and add a starting grid to get a more appealing result.
The process is simple, we grow each point of the obtained spline into a circle of radius r and fill it with the given color.
To add the grid that marks the begining of the track we get the first and fourth (this can be easily modified) points in the spline and compute a vector perpendicular to the one obtained from those two points. Then we rotate the grid by the angle of the perpendicular vector and place it at the position of the first point in the spline.
I have also tried to, given a minimum and maximum track angle corners, draw kerbs on the track. This hasn't been really successful. Anyway, below you can see some results of the obtained tracks after adding the kerbs.
- Add command line arguments.
- Fix inconsistencies in data structures (numpy arrays, lists, tuples, etc.).
- Refactor code when track drawing is finished.
- Test other interpolation methods to obtain the smoothed track.
- Tune parameters.
- Find a better method to detect corners.
- Add kerbs to corners.
- Add checkpoints to track
- Improve and tune subsystems. Play with parameters.
- Divide surface in a grid
- Refactor code
- IGVC parameters:
constants.pynow includes IGVC-relevant parameters (course dimensions, speed limits, run time, pixels-per-foot, etc.). - Scale marker: generated
track.pngincludes parking spot rectangles and a small scale bar to help visualize real-world sizes (parking spot ~9x18 ft).
The generator now uses a single source-of-truth unit system:
- Track and rule dimensions are defined in feet.
- Raster and SVG output use a uniform pixels-per-foot scale for both x and y axes.
- JSON exports include pixel, feet, and meter centerline coordinates.
- OpenSCAD export converts coordinates to millimeters.
Key formulas used in constants.py:
pixels_per_foot = min(WIDTH / course_width_ft, HEIGHT / course_height_ft)feet_per_pixel = 1 / pixels_per_footpixels_per_meter = pixels_per_foot / 0.3048pixels_to_mm = 304.8 / pixels_per_foot
To keep physical units consistent, the IGVC course area is centered in the canvas when aspect ratios differ. Exports include course width/height and pixel offsets so downstream tools can reconstruct the exact metric frame.
USD obstacle generation now supports a competition-style placement mode:
- Density-based count from track length (obstacles per 100 ft).
- Guaranteed minimum free corridor width around each placed obstacle.
- Minimum spacing between obstacles and minimum longitudinal spacing along the route.
- Start/finish exclusion zone to avoid immediate obstruction at the run boundary.
- Pattern-based placement (single, staggered pair, slalom triplet) with weighted sampling.
- Tighter default packing tuned for competition-like clutter while preserving passability.
CLI usage:
--generate-usdto export the USD field.--num-obstacles 0to use density-based AutoNav-style placement.--num-obstacles N(N > 0) to force a fixed obstacle count.--save-obstacle-debug true|falseto toggle obstacle debug image output.--obstacle-debug-image path.pngto choose where the overlay image is written.



