Repository navigation
CARLA maps
The CARLA map modules read an OpenDRIVE file into a road network, answer CARLA's map queries on it, and build its road surface as meshes. They port CARLA's opendrive/parser/*, road/* and road/MeshFactory at commit 1360bb9.
See CARLA for the frame, the sensors and the LiDAR, and Extensions for the other extensions.
load_opendrive_file reads an .xodr file. load_opendrive reads the same text from a string.
from extensions.carla.map import Waypoint
from extensions.carla.opendrive import load_opendrive_file
from extensions.carla.road_info import LaneId, RoadId, SectionId
from math.vector3 import Vector3
var map = load_opendrive_file("assets/carla/town.xodr")
var here = map.waypoint(Vector3(20, 1.75, 0)).value()
var ahead = map.next(here, 5.0)
var pose = map.compute_transform(ahead[0])waypoint gives the waypoint under a point in CARLA's frame, or none. next gives every waypoint 5 meters ahead. compute_transform gives the pose of a vehicle there.
The test town is assets/carla/town.xodr. Road 1 runs east into junction 100. Road 10 goes on to road 2 and road 11 turns right onto road 3. Roads 5, 6 and 7 stand alone and carry the other records.
| Module | What it holds |
|---|---|
road_info |
The ids, the lane kinds, every RoadInfo record, InformationSet and LaneMarking. |
road |
Road, LaneSection, Lane and LaneKey. |
map |
Map, Waypoint, Junction, Signal, Controller, RoadObject, the signal types and the deformation. |
map_builder |
MapBuilder, which joins the parser's pieces into a Map. |
opendrive |
The parser and pugixml's attribute readers. |
mesh_factory |
MeshFactory and the map's meshes. |
A Waypoint is a road id, a lane section id, a lane id and an s. The s is a Float64 in meters. CARLA steps a waypoint 10 double epsilons inside a section's edge, and a Float32 cannot hold that step.
Two waypoints are equal when the road, the section and the lane match and floor(200 s) matches. This is CARLA's hash.
| Question | Method |
|---|---|
| Where is a waypoint? |
compute_transform, lane_width, lane_type
|
| Which waypoint is near a point? |
closest_waypoint_on_road, waypoint
|
| Which waypoint is certifiably nearest a point? |
certified_closest_waypoint_on_road, certified_waypoint
|
| Which waypoint is at a road, lane and s? | waypoint_xodr |
| What is ahead or behind? |
next, previous, successors, predecessors
|
| Where does the lane end? |
next_until_lane_end, previous_until_lane_start
|
| What is beside? |
right, left
|
| Which marks bound the lane? |
mark_record, right_lane_marking, left_lane_marking, lane_change
|
| Which marks does a move cross? | calculate_crossed_lanes |
| Which signals are ahead? |
signals_in_distance, landmarks_in_distance, landmarks_of_type_in_distance
|
| Which signals are there? |
all_signal_references, all_landmarks, landmarks_from_id, all_landmarks_of_type, landmark_group
|
| Where are the crosswalks? | all_crosswalk_zones |
| Which waypoints cover the map? |
generate_waypoints, generate_waypoints_on_road_entries, generate_waypoints_in_road, generate_topology
|
| What is in a junction? |
junction, junction_waypoints, compute_junction_conflicts, is_junction, junction_id
|
Right and left are as the lane's traffic sees them. A lane that runs against s faces the other way, so its yaw gains 180 degrees.
closest_waypoint_on_road and waypoint are CARLA's queries. They search CARLA's own segment partition, so they are fast. They step from the segment's start by the foot's plan fraction of the segment times the segment's road-s span. CARLA steps by the plan distance along the chord instead. The two steps differ when a lane offset, a lane width or a curve changes the lane's plan speed. Inside one curved segment, the step keeps the chord's linear approximation of road s.
certified_closest_waypoint_on_road and certified_waypoint prove lane selection with bounds on the stored Float64 lane centers.
A returned station can be an approximate witness within the search accuracy limit.
The certificate records whether it proves an exact minimizing witness.
These queries are slower. They raise when their work budget cannot separate two candidates. See cross-candidate certificates and map budgets.
The certified query uses these proofs:
- Lane point distance: exact order of stored lane centers, and the on-road width test
- Lane seeding: bounded starting parameters for a SPIRAL search
- Fixed LINE heading bounds: the constant heading of a LINE segment
- Directed value bounds: tighter bounds on ideal expressions
- Sampled value bounds: derivative-free bounds on sampled lane covers
- Rounded ARC certificates: stored-point minimum proofs on an ARC
LaneType is a bit mask. A query takes a mask, such as LANE_DRIVING | LANE_SHOULDER, and keeps the lanes whose type shares a bit with it.
Road.nearest_lane is the separate fixed-s OpenDRIVE query.
Its centers and returned distance retain Float64 precision.
A known waypoint uses the derivative of its evaluated offset-plus-width centerline for heading and pitch. This covers all five reference geometries, inner-lane widths, lane offsets, and both traffic directions. The query and transform share one Float64 lane center and keep zero roll. See lane orientation for record boundaries, singular tangents, rounding and remaining limits.
Canonical SPIRAL lane positions use compensated Sum2 accumulation of the
stored Gauss-Legendre terms. The stored nodes, weights, term order, polynomial
trigonometry, heading, and derivative arithmetic stay the same. This change
can alter a fixed-s lane position, the closest station, and scenario replay.
It applies to Road.lane_transform, Map.compute_transform, and lane queries.
The separate RoadGeometry and road-reference point routes keep their
existing arithmetic.
The Sum2 bound encloses the stored polynomial computation. It is not a true-clothoid accuracy guarantee. The ideal full-Jet and value-only models share the new scalar-error bound. Optional envelopes use the same bound. The search keeps its accuracy limits, cumulative work caps, and tie rules.
Map construction and nearest queries require round-to-nearest arithmetic with gradual underflow. Canonical SPIRAL evaluation has the same requirement. Fresh checks refuse unsupported rounding, flush-to-zero, or denormals-are-zero modes. Cached proofs do not bypass those checks. Production code does not change the caller's floating-point controls. See CPU mode controls for maintained negative-mode tests and platform qualification limits.
generate_topology keeps each dead-end driving lane. Its terminal waypoint uses the known road, section and lane with an s in double precision. It does not look the endpoint up again through waypoint_xodr. This keeps the endpoint in its own section when rounding would select the next section or reject the road end. Connected pairs keep their existing order.
next_until_lane_end and previous_until_lane_start follow the unique lane path within the starting road. They stop at a road boundary, an unlinked section boundary or a branch. The final waypoint is the reachable endpoint in the requested direction. A start already at or beyond that inward endpoint returns an empty list.
The inward offset is capped at one quarter of the section length so tiny positive sections retain valid endpoints. If no interior value is representable, the boundary is used. A positive final remainder still emits the endpoint, even below the usual inward offset.
The input s must be finite and inside the specified lane section. Shared endpoints are valid for either adjacent section. The spacing must be finite and greater than EPSILON. A spacing that cannot advance the waypoint raises an error.
The endpoint is resolved before sampling. A large interval does not traverse a different road. Ordinary forward samples keep the existing spacing and order. Exact endpoints do not add a duplicate sample.
junction_box encloses the centers of nonzero lanes selected by LANE_ANY
on each connecting road. This mask excludes LANE_NONE. It includes every
section, even when lane links stop or change lane id.
It evaluates increasing road s for both traffic directions. It includes the
exact section endpoints and both sides of each record boundary.
It does not follow a successor road. Repeated connections do not change the result. A junction without lanes keeps CARLA's empty-box sentinel. Section bounds use the stored next-section or road endpoint. They do not reconstruct it by adding a rounded section length. This keeps valid decimal endpoints such as a 10.2 m section start on a 50.1 m road in range.
The bound covers the supported lane-center model, not the lane surface. That model includes line, arc, spiral, poly3 and paramPoly3 geometry, lane widths, lane offsets and elevation. Poly3 and paramPoly3 use the existing sampled position and tangent tables, including their extrapolated tail. Superelevation, crossfall and shape remain outside the supported model.
The approximation has an explicit error budget:
- Split at geometry starts and ends, table knots, section boundaries, and all width, offset and elevation record starts.
- On each smooth span, bound the second derivative. Subdivide until the maximum coordinate distance from a chord is at most 0.01 m. Add that distance to the sampled box. Constant-offset arcs instead evaluate the cardinal headings that can contain an extremum.
- Add a Float32 rounding allowance of four machine epsilons times the coordinate and offset scale, with a 1 m floor. Add coefficient-scaled Float64 Horner error for the road-s cubics. A large road s can make this numerical allowance much larger than 0.01 m. Arc bounds also include phase and radius cancellation error. Unresolved arc phases use a full-circle-sized numerical allowance.
- For a spiral, also add
1.1e-7 * geometry.lengthmeters per plan axis. This covers twice the five-point Gauss-Legendre remainder bound for the supported evaluator. It is separate from the chord error. - A singular paramPoly3 tangent or a span that needs more than 65,536 subdivisions uses a wider envelope. It encloses the reference chord, its curvature error, and the complete lateral-offset disk. Elevation uses its cubic envelope. This fallback has no 0.01 m tightness claim.
These are conservative numerical bounds, not exact extrema. The geometric proof applies to finite record arithmetic. Non-finite coefficient or subdivision arithmetic raises an error. Evaluated locations and padded bounds must fit in finite Float32 coordinates. This contract does not repair unrelated geometry evaluation or nearest-lane limitations.
For a smooth coordinate with second derivative bounded by M, the chord
error is at most M * h * h / 8. For a lane center P + t*n, a sufficient
plan bound is |P''| + |t''| + 2*|t'|*|heading'| + |t|*(|heading''| + |heading'|^2). Cubic Bernstein control values bound the
width, offset and elevation terms. A parametric tangent uses the minimum
length of its interpolated derivative vector over the complete span.
Corrected boxes can add junction road conflicts and stop/yield check boxes. They can also change mesh-region selection and the expanded mesh boxes. Traffic-manager waypoint junction flags use road topology, not these boxes. Scenario replay can therefore differ where the old box omitted a curved interior. Ordering remains deterministic.
Road.nearest_lane selects a lane at one supplied s in the OpenDRIVE frame.
It retains Float64 centers and compares their stored-point distances exactly.
It returns a scale-safe approximate Float64 distance and checks its finite range.
This helper visits all eligible lane centers and preserves exact-tie ordering.
It does not call or change the Map nearest-waypoint search.
See fixed-s nearest lane queries for limits and record rules.
bench/carla_segment_numerics_bench.mojo times ordinary segment queries.
bench/carla_road_fixed_s_bench.mojo times this fixed-s query.
A road with rule="LHT" keeps traffic to the left. Its left lanes run with s and its right lanes against it. right, left, the lane change and the sign placement all follow the rule.
MapBuilder.build joins the pieces in CARLA's order.
- It links each lane to the lanes it leads to, within its road, onto the next road, or through a junction.
- It removes a signal reference whose every validity is lane 0 to lane 0.
- It sorts each road's and each lane's records by s.
- It places each signal on its road, or at its inertial position.
- It gives a reference with no validity the lanes that face it.
- It tells each signal which controllers hold it, through the junctions that name them.
- It cuts each lane into straight segments for the nearest-waypoint search.
- It boxes each junction and finds the junction roads that cross.
- It moves each sign that stands on a driving lane off that lane.
The segments are in extensions.carla.rtree.SegmentCloudRtree.
segment_count() and segment() return this nearest-waypoint index.
They do not promise a fixed partition. Accuracy changes can add segments.
The lane order and index tie rules stay deterministic.
The quarter-point chord target is one millimeter. A required split needs an interior Float64 road-s value. Construction raises a resolution error when that value is unavailable. A positive nonterminal sampling step must also advance in lane order. A rounded unchanged step raises a resolution error. Terminal zero-span index entries remain valid.
See road-s resolution.
Sampling does not bound unsampled extrema. Candidate admission uses a separate full-center enclosure and the corrected R-tree distance bound. An unknown bound keeps a candidate. The minimum search proves candidate dominance and strict on-road status.
It resumes overlapping candidates without resetting their work budgets. If the remaining budget cannot prove the result, the query raises an accuracy error. It does not return an unproved waypoint or off-road result.
The lane correction controls explain the
intentional pose, minimum, index and mesh changes. This work is still held
for final qualification. Border-only lanes get width records from their
borders; see CARLA lane borders. Global construction and continuous-query work use typed
MapBuildBudget and MapQueryBudget policies, with explicit exhaustion and
pre-admission of nested lookup, ordering and refinement work. See
spatial map resource budgets for defaults, logical work
units, compatibility behavior and validation controls.
MeshFactory returns a BufferGeometry in CARLA's frame. Each geometry has per-vertex normals, UVs in meters and one group for each surface kind. to_three_frame turns a geometry into the three.js frame.
| Surface kind | What it is |
|---|---|
ROAD_SURFACE |
The driving surface. |
SIDEWALK_SURFACE |
The top of a sidewalk. |
CURB_SURFACE |
The sides of a sidewalk. |
WALL_SURFACE |
A safety wall on a section's outer edge. |
CROSSWALK_SURFACE |
A crosswalk. |
WHITE_MARK_SURFACE |
White paint. |
YELLOW_MARK_SURFACE |
The yellow center line. |
On a lane, u is the offset from lane 0 and v is s. On a curb or a wall, u is the height. On a crosswalk, u and v are x and y. The uv1 attribute holds CARLA's own grid coordinates where CARLA writes them.
The map functions are generate_mesh, generate_chunked_mesh, generate_ordered_chunked_mesh_in_locations, trees_transform, all_crosswalk_mesh, generate_line_markings and junctions_bounding_boxes.
This port keeps CARLA's numbers except for the corrections listed here.
- Waypoint orientation follows the geometric centerline tangent, including lateral and curvature derivatives. Pitch uses vertical speed over actual horizontal speed, with the sign required by the corrected CARLA rotation basis. CARLA used a lateral slope as an angle and a raw elevation grade as positive pitch. See issue #485 and the orientation contract.
- The fixed-s
Road.nearest_lanequery compares every eligible Float64 center before rounding. It returns a scale-safe Float64 distance in the OpenDRIVE frame. It removes CARLA's early-distance stop because rounded centers can make an outer lane closer. See fixed-s query precision and limits. - The default
closest_waypoint_on_roadandwaypointqueries map the foot's plan fraction of a segment to road s. The pinned CARLAMap.cppsteps by the plan distance along the chord. On a lane with a sloped or curvedlaneOffset, or with a sloped lane width, that distance is not road s. A 100 m road withlaneOffsetb=1 is the reproducible counterexample: CARLA's step puts the center point at s=70.71, andwaypointreturns no lane. The port deliberately corrects that behavior. Tests query exact lane centers on curved, sloped and low-curvature offsets, sloped and curved widths on both lane signs, and section boundaries. See issue #302. - The certified nearest-waypoint queries minimize the lane-center distance. They do not treat distance along an offset chord as road s. Internal selection and strict on-road checks keep the Float64 center. Only the public transform narrows the position.
- The nearest-waypoint index splits at record boundaries and for lane-center chord error. Its public count can differ from CARLA's heading-only partition. A required split without an interior Float64 road-s value raises a resolution error.
- A width-record kink prevents the straight-lane mesh shortcut. The existing mesh resolution then adds rows through that section. MeshFactory does not use the nearest-waypoint index as its mesh partition.
- Topology retains dead-end lanes and their section identity. The pinned CARLA
Map.cppnarrows the endpoint to a float before lookup. This can drop an increasing-s lane at the road end. The port deliberately corrects that behavior. See issue #285. - Backward lane traversal measures the remainder toward the lane start. The pinned CARLA
Waypoint.cppuses the forward remainder for its final backward step. That can leave the starting road or fail at an isolated end. The port deliberately corrects that behavior and handles exact and unlinked section endpoints. See issue #286. - Junction bounds include reverse-running curved lane interiors. The pinned CARLA
CreateJunctionBoundingBoxesuses a signed ten-step interval and skips those interiors. The port uses the bounded approximation above. A 100 m semicircle with a positive RHT lane is the reproducible counterexample. See issue #487. - CARLA walks roads, junctions and signals in hash order. This port walks them in order of id.
- CARLA computes a point in single precision. This port computes in double and rounds where CARLA returns a float, except for the fixed-s nearest-lane correction.
- Fixed-s nearest-lane selection keeps wide stored centers and checks every center. It no longer turns narrowed centers or underflowed squares into false ties. See issue #604 and the precision limits.
- A spiral uses Gauss-Legendre quadrature, as CARLA explains. Canonical lane positions use compensated stored-term summation, which can change positions and closest stations.
- The segment search breaks a tie by the order the segments were made. Boost leaves that order open.
- A lane link that names no lane is dropped. CARLA stores a null pointer and crashes on it.
- A signal reference that names no signal is refused. CARLA crashes on it.
- CARLA loops forever on a lane with no road mark at its section's start. The mark generator stops there.
- A mesh keeps the triangles of one surface kind together. CARLA interleaves a sidewalk's curb and top row by row.
- A clockwise crosswalk outline is turned so that its face points up.
- A junction of more than two connections is built from its lanes. CARLA uses marching cubes from a third-party library there.
- The lateral profile: superelevation, crossfall and shape. CARLA reads it and never stores it.
- The traffic groups in
userData. CARLA's parser for them is empty. -
Map::GenerateWalls. CARLA declares it and does not define it. -
SDFToMesh, which needs the MeshReconstruction library.
The geographic reference comes from extensions.carla.geo. See CARLA geometry.
Road and lane speed records keep their source number and unit. The checked runtime accessor returns Velocity64. See OpenDRIVE speed limits for defaults, road keywords, signal validation and simulation conversion.
Tutorials
How-to
Reference
- Scene graph
- Rotations
- Cameras
- Geometry
- Geometry addons
- Lofts and clipping groups
- Sculptor
- Procedural generators
- Meshes and assets
- Lines
- Points and sprites
- Helpers
- Scene objects
- Animated objects
- Raycasting
- Curves and paths
- Animation
- Skinning
- Materials
- Node materials
- TSL functions
- Lights
- Lighting addons
- Fog
- Textures
- Renderer
- Renderer hooks and material flags
- Rasterization
- GPU backend
- Render target
- Post-processing
- GPU computation
- Compute nodes
- Progressive light map
- Gaussian splats
- Voxel global illumination
- SVG renderer
- Image files
- Image decode queue
- Model files
- More model files
- Exporters
- Scene JSON
- Windowing and controls
- Math
- Norm consumers
- Math addons
- Units
- Coverage tool
- Commands
- Examples
- Benchmarks
- Extensions
- Shared physics
- Physics query snapshots
- Continuous collision
- Tick force restoration
- Water
- Animals
- Buildings
- CARLA
- Femur
- Tibia
- Fibula
- Patella
- Knee
- Muscles
- Vessels
- Lymph
- Nerves
- Integument
- Leg
- Foot
- Pelvis
- Torso
- Arm
- Hand
- Head
- Genome
- Game humanoid
- Humanoid fidelity
- Audio-aligned game faces
- Converted assets
- Mesh quality
- Segment inertia
Explanation
- Software rasterizer
- Scene graph as an array
- Linear color
- Normals are not colors
- Perspective correction
- Fixed-point coverage
- Per-fragment shading
- Mipmaps
- Sorted transparency
- Types and checks
- Render hooks as a trait
- Shared CPU and GPU code
- Bands and threads
- PNG structure
- Extensions beside the port
- CUDA teardown hang
- Mojo compiler hang