Skip to content

Map format requirements

Foretify supports various native map formats. For each map format, a code component that implements the Map Support Package (MSP) interface is required. These Map Support Packages process native maps into a Foretify-compatible representation. These MSPs are not necessarily part of Foretify distribution.

Rather than imposing requirements on native maps, this document describes the data required by Foretify’s internal map representation, as well as additional data that the MSP can supply.

Terminology

While the most basic terms describing a road map are road and lane, they are commonly used with different meanings in different contexts.

Terms used in this document:

  • directed-road is a one-way road or one side of a two-way road.

  • msp-road is a longitudinal interval of a directed-road, including all its lanes and having a constant number of lanes. lanes in this context includes driving lanes, sidewalks, shoulders and so on.

  • msp-lane is a single lane of an msp-road.

Required data

Map topology

  • Map topology is represented by two directed graphs:

    • A directed graph of msp-lanes.

    • A directed graph of msp-roads.

    Graph directionality corresponds to traffic driving direction. The directionality of roads that have no driving lanes is arbitrary. Bi-directional driving lanes are currently not supported.

  • msp-lanes in a msp-road are ordered from right to left relative to the driving direction.

  • msp-road Rb is a next of msp-road Ra if and only if some msp-lane Rb.lanes[i] is a next of msp-lane Ra.lanes[j].

  • msp-lanes (and subsequently msp-roads) may only connect at their ends.

  • A msp-lane may have at most one next msp-lane per next msp-road.

  • A msp-lane may have at most one previous msp-lane per previous msp-road.

Topology semantics

Topology corresponds to movement in the following manner:

  • Normally driving from msp-road Ra to Rb is possible or allowed only if Rb is next of Ra

  • Normally driving from msp-lane La to Lb is possible or allowed only if

    • Lb is next of La or

    • La and Lb are neighbors in the same msp-road, in other words, La=R.lanes[i] and Lb=R.lanes[i+1] for some msp-road R.

      • In this case movement is considered to be a “lane change”.

      • An edge case of a “lane change” is if Lc is a next of La and a neighbor of Lb.

Map geometry

Map geometry is represented in a 2D Euclidean plane with supplementary data on surface elevation in the corresponding 3D Euclidean space.

Length

  • The nominal length of a msp-lane is the length of the reference line going through the center of the lane (projected to the x,y-plane). Each msp-lane node in the graph contains its nominal length.

  • The nominal length of a msp-road is not well defined. It should represent some reference line describing the road’s shape (projected to the x,y-plane). Each msp-road node in the graph contains its nominal length.

  • The MSP interface provides bijection APIs between longitudinal-offset on different msp-lanes of the same msp-road, and between longitudinal offsets on the msp-lanes and the msp-road.

    These bijections should represent for example the corresponding longitudinal-offsets of cars driving side by side on different msp-lanes.

Shape

The MSP interface provides API methods that given a msp-lane and a longitudinal offset along its center reference line (projected to the x,y-plane) return:

  • The corresponding global x,y,z coordinates in Euclidean space. See Foretify's coordinate system.

  • The width of the msp-lane at the given offset (projected to the x,y-plane).

  • The angle of the msp-lane at the given offset (on the x,y-plane relative to the x-axis).

Geometry and connectivity

Topologically connected lanes are required to be geometrically connected as well. For example, if msp-lane Lb is a next of msp-lane La then global_coordinate(La, La.length) == global_coordinate(Lb, 0)

Restrictions:

  • msp-lanes in the same msp-road must not overlap.

  • Gaps between msp-lanes in the same msp-road are forbidden. In other words, any point inside a msp-road is necessarily on one of its msp-lanes.

Lane usage

msp-lane is assigned a set of allowed usages, one of none, driving, shoulder, biking, sidewalk, border, parking, rail. By default Foretify plans car trajectories and drives cars only on msp-lanes with driving usage.

Additional data

Foretify has the following map-related items that can be populated by the MSP:

  • speed limits

  • opposite directed-roads that connect the two sides of a two-way road

  • road signs (stop, yield, etc)

  • traffic-lights

  • lane markings (dashed, solid, etc)

  • route elements (a high level classification of routes on the map by predefined sets of properties)

Speed limits

Foretify's MSP interface provides an API method to retrieve the speed limit at a given offset in a msp-lane.

Opposite roads (the other side of a two-way road)

Foretify does not make a geometric analysis to determine which msp-roads are opposite sides of a “real” two-way road. It is up to the MSP to provide this information. Using this information, Foretify infers the road_with_opposite route element.

Static road signs

The MSP should be able to associate signs with:

  • The lane or lanes they control. A stop sign, for example, may control specific lanes entering a junction.

  • A logical position, such as the stop-line for a stop sign.

Currently Foretify only supports stop, yield and other sign types

Traffic lights

Foretify uses the following structures to represent traffic lights:

  • The struct msp_traffic_light_bulb represents a single physical bulb. It has the following:

    • color is one of unknown, red, yellow, green, blue, white

    • icon is one of unknown, none, arrow_straight, arrow_left, arrow_right, pedestrian, walk, dont_walk, bicycle, countdown

    • map_id (string) is an ID specified by the native map format and shared with the simulator.

  • The struct msp_physical_traffic_light represents a single traffic-light “box” of bulbs. It has the following:

    • A list of msp_traffic_light_bulb is for example, the classic red-yellow-green

    • map_id (string) is an ID specified by the native map format and shared with the simulator.

    • msp_traffic_light is the “logical traffic-light”, a grouping of msp_physical_traffic_light instances that have the same state.

  • The struct msp_traffic_light represents a set of traffic-light boxes that control the same lanes. In other words, a set of traffic-light boxes that under valid operation always have the same state. (Multiple boxes that correspond to the same logical traffic-light are commonly placed in different locations in the junction to improve visibility.) It has:

    • A list of msp_traffic_light_bulb

    • A list of bulb-states where the state of each bulb is one of unknown, is_off, is_on, is_flashing

    • A list of msp_physical_traffic_light instances

    • map_id (string) is an ID specified by the native map format and shared with the simulator.

The level of specification required by the native map depends on both simulator requirements and on scenario requirements. For example, the simulator may provide traffic-light control APIs that receive either the ID of a logical traffic-light or the ID of a physical traffic-light or both.

The MSP should at least be able to:

  • Instantiate logical traffic-lights

  • Associate the logical traffic-lights with:

    • The lanes they control. A traffic light for example may control specific lanes entering a junction.

    • A logical position, such as the stop-line for a red light.

Lane marking

The MSP interface provides an API method to retrieve a lane-mark at a given offset in and side of a msp-lane. A lane-mark has:

  • line_kind is one of none, solid, broken, solid_solid, solid_broken, broken_solid, broken_broken, botts_dots, grass, curb, edge

  • line_color is one of blue, green, red, white, yellow, orange

Route elements

Route elements were previously called road elements. In this section the terms are used interchangeably.

Route elements are a general mechanism used by Foretify to classify paths on the map according to sets of properties:

  • A route element type specifies a set of properties.

  • Occurrences of a specific type are paths on the map, each associated with specific values for the type’s properties.

  • Paths are defined by:

    • A list of connected msp-roads

    • A start offset on the first msp-road in the list

    • An end-offset on the last msp-road in the list

    • A range of msp-lanes for each msp-road in the list

Example

The route element type road_curvature classifies paths on the map according to their curvature.

# road_curvature corresponds to a piece of road that does not cross junctions and on which:
# (a) curvature does not change by more than a factor of T, i.e., max_radius/min_radius <= T
# (b) curvature does not change direction.
#
struct road_curvature inherits road_element:
    # min/max_radius:
    # - value is always positive, 'direction' field is used to specify curve direction.
    # - For a straight road interval min_radius and max_radius are MAX_DISTANCE
    #
    min_radius: length
    max_radius: length
    # direction of the curve ('neither' for zero curvature)
    #
    direction: curve_direction

MSP-provided elements

Route element occurrences are added to the map after the MSP has been loaded. In other words:

  • The msp-lane graph and msp-road graph have been populated.

  • The map-geometry related info is initialized.

  • The additional data specified above (signs, opposite roads, speed-limits, and so on) has been added.

Foretify compiles most route element occurrences from the loaded map to represent higher-level structures, such as road_curvature or junction. However, Foretify provides the following hooks for the MSP also to add route element occurrences:

# Marking of MSP specific road elements
# This method is called after all non msp-specific road elements are already marked.
# When map-caching is active, the road_elements added by this method are cached along with the map to
# include road_elements for a given map that do not change between scenarios. Scenario-specific elements are 
# marked in mark_volatile_road_elements().
#
def mark_road_elements() is empty

# Marking of MSP specific road elements that are specific to a single scenario or group of scenarios.
# These elements are not cached and will be re-computed in runs that load the map from cache.
#
def mark_volatile_road_elements() is empty

For example, you can use mark_road_elements() to add crosswalk and tunnel route elements.

See route_elements for more detailed information.