Skip to content

Costing Model

The costing model determines how the router evaluates paths. Each edge and each transition between edges has a cost (what the A search minimizes) and a time* (real-world elapsed seconds).

Cost vs Time

Cost is an abstract value the router minimizes — it includes time but also penalties for undesirable road attributes (tolls, poor surfaces, turns). Time is the estimated real-world elapsed seconds. A route with lower cost may have higher time if it avoids penalties.


DynamicCost trait

All cost models implement the DynamicCost trait:

pub trait DynamicCost {
    fn edge_cost(&self, edge: &DirectedEdge, density: u32) -> Cost;
    fn transition_cost(&self, edge: &DirectedEdge, node: &NodeInfo, pred: &PredInfo) -> Cost;
    fn allowed(&self, edge: &DirectedEdge, pred: &PredInfo) -> bool;
}
  • edge_cost — cost to traverse a single edge
  • transition_cost — cost at the junction between two edges
  • allowed — access and turn restriction filtering

The Cost struct carries two values:

pub struct Cost {
    pub cost: f32,  // abstract cost (what A* minimizes)
    pub secs: f32,  // real elapsed seconds
}

Auto (driving) cost

Edge cost

The driving edge cost is:

elapsed_time = length / speed
cost = elapsed_time * factor

Where factor blends several components:

  • Speed factor — pre-computed lookup table with 256 entries indexed by speed (kph). Lower speeds get a higher factor, biasing routes toward faster roads. The table is built once at startup from the use_highways and use_distance parameters.
  • Highway factor — scales motorway/trunk edge costs based on use_highways preference. At 0.0, highways are 3x more expensive; at 1.0, they're cheaper.
  • Toll factor — scales toll road costs based on use_tolls preference. At 0.0, toll roads get a 6x multiplier; at 1.0, no penalty.
  • Surface factor — penalizes poor road surfaces based on surface_factor. Surface types range from PavedSmooth (no penalty) to Impassable (maximum penalty).
  • Distance factor — when use_distance > 0, blends length into cost, producing shorter (not just fastest) routes.

Transition cost

The transition cost at a junction depends on:

Factor Source Description
Turn type Edge pair data Right, left, sharp, U-turn, etc. (8 types)
Stop impact Edge pair data 0 (free-flow) to 7 (full stop)
Name consistency Edge pair data Whether the road name continues
Traffic signal Node attribute Adds signal_penalty seconds
Density Node attribute 0-15 scale, multiplies turn delay
Destination-only Edge attribute Adds destination_only_penalty
Toll booth Edge attribute Adds toll_booth_cost
Service road Edge attribute Adds service_penalty

Turn cost formula

base_cost = TURN_COSTS[turn_type][stop_impact]
density_factor = TRANSITION_DENSITY_FACTOR[density]
cost = base_cost * density_factor

Where:

  • TURN_COSTS is a pre-computed [8][8] table (8 turn types × 8 stop impact levels). U-turns are most expensive; straight-throughs at stop impact 0 are free.
  • TRANSITION_DENSITY_FACTOR is a 16-entry table indexed by node density (0-15). Dense urban areas (density 15) multiply turn costs by ~4x compared to rural areas (density 0).

Name consistency adjustment

When the road name continues across a junction (name-consistent), the transition cost is heavily reduced — the router treats it as staying on the same road. When the name changes, maneuver_penalty seconds are added (cost only, not time) to penalize unnecessary turns.

Density

Density is a 4-bit value (0-15) stored on each node in the tile. It approximates the surrounding road network complexity:

Density Environment Turn cost multiplier
0-3 Rural / highway 1.0x
4-7 Suburban 1.2-1.5x
8-11 Urban 2.0-3.0x
12-15 Dense urban core 3.5-4.0x

Hierarchy transitions

When crossing hierarchy levels (e.g., level 2 local road to level 1 arterial), the per-pair data (turn type, stop impact, name consistency) comes from a different-level node and is unreliable. At these transitions, Calculon:

  1. Applies base penalties only (toll, destination-only, service road)
  2. Uses an estimated stop impact of 4.0 (moderate intersection)
  3. Detects near-U-turns by comparing headings across the transition — if the turn is within 30° of a U-turn, adds a full reverse-turn penalty

Turn restrictions

The allowed() function filters edges based on:

  • Access mask — the edge must have forward access for the travel mode
  • Turn restrictions — one-way violations and conditional restrictions encoded in the tile
  • Not-thru pruning — avoids not-thru edges unless the path started on one

Bicycle cost

Edge cost

elapsed_time = length / cycling_speed
cost = elapsed_time * factor

Where factor adjusts for:

  • Road classuse_roads scales cost on high-traffic roads. At 0.0, Primary roads get a 5x penalty; at 1.0, no penalty.
  • Surface qualityavoid_bad_surfaces penalizes gravel, dirt, etc. Compacted surfaces add 20-50% cost; impassable surfaces block the edge entirely.
  • Living streetsuse_living_streets reduces cost on residential streets

Transition cost

Similar to auto but with:

  • No toll booth or service road penalties
  • gate_penalty for barriers (default 300 seconds — gates are very expensive for cyclists)
  • Lower turn costs overall (cyclists turn more easily)

Access filtering

Cyclists can use: roads with bicycle access, cycleways, living streets, footways (with dismount penalty). They cannot use: motorways, trunk roads, or edges without bicycle access.


Pedestrian cost

Edge cost

elapsed_time = length / walking_speed
cost = elapsed_time * factor

Where factor adjusts for path type:

Path type Default factor Effect
Walkway / footway 1.0 Preferred
Sidewalk present 1.0 Preferred
Living street 0.6-1.0 Depends on use_living_streets
Alley 2.0 Avoided
Driveway 5.0 Strongly avoided
Steps +30s penalty Per staircase

Additional factors

  • Lightinguse_lit adds cost to unlit edges (0.0 = don't care, 1.0 = strongly prefer lit roads)
  • Hiking difficulty — edges above max_hiking_difficulty (SAC scale 0-6) are blocked
  • Hill avoidanceuse_hills adjusts cost based on grade (steeper = more expensive)

Access filtering

Pedestrians can use: footways, walkways, sidewalks, crossings, living streets, paths, steps. They cannot use: motorways, trunk roads, or edges without pedestrian access.


Shortest mode

When shortest: true, the cost model switches to pure distance-based routing:

  • Edge cost becomes proportional to length only, ignoring speed and road class
  • Turn costs are still applied to avoid unreasonable maneuvers
  • The use_distance parameter is ignored (effectively set to 1.0)
  • Useful for debugging and comparing with other routers

Lookup tables

All cost models use pre-computed lookup tables built at construction time:

Table Size Indexed by Purpose
Speed factor 256 entries Speed (kph) Edge cost multiplier
Turn costs 8×8 entries Turn type × stop impact Base transition cost
Density factor 16 entries Node density (0-15) Transition cost multiplier
Highway factor Per road class RoadClass enum Highway preference scaling
Surface factor Per surface type Surface enum Surface quality penalty

Tables are computed once per costing instance (at request time if per-request options differ from defaults) and stored inline. Zero allocations during routing.