destination: 39-84 46th St, Sunnyside (OSM way 241831843); durable data location; profile-sensitivity experiment
- destination changed from generic 'Queens NY' to the real address, geocoded offline from the NY PBF (addr:street=46th Street, addr:housenumber=39-84, postcode 11104 -> 40.74707,-73.9181) - OSRM tree moved /tmp/osm-build -> /home/gmp/osm-build (durable); scripts default W to $HOME/osm-build; LD_LIBRARY_PATH export for the baked-in RPATH; cmake stub paths re-pointed - profile experiment: profiles/car-us.lua (US-tuned speed table on stock car.lua) -> Lincoln->Sunnyside 406 -> 377 min vs Valhalla 327; README documents the mechanism (motorway=90 x speed_reduction 0.8 = 72 km/h effective on untagged US interstates) - bench goldens re-recorded for both backends with new destination; both 26/26 PASS, integration tests pass on both routers
This commit is contained in:
parent
0c4a1f9f60
commit
916f9eb503
|
|
@ -92,7 +92,7 @@ CMake config files — boost release tarballs ship no CMake support) and
|
||||||
osmium-tool; then it builds OSRM 26.4.1, merges the 4 state PBFs
|
osmium-tool; then it builds OSRM 26.4.1, merges the 4 state PBFs
|
||||||
(osrm-extract takes one input), extracts (~8 GB peak RAM, ~4 min),
|
(osrm-extract takes one input), extracts (~8 GB peak RAM, ~4 min),
|
||||||
partitions, customizes, and serves on `:5000`. Artifacts live in
|
partitions, customizes, and serves on `:5000`. Artifacts live in
|
||||||
`/tmp/osm-build` by default (set `W=` for a durable location).
|
`$HOME/osm-build` by default (override with `W=`).
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
ROUTER_BACKEND=osrm ROUTER_URL=http://localhost:5000 go test -tags integration ./...
|
ROUTER_BACKEND=osrm ROUTER_URL=http://localhost:5000 go test -tags integration ./...
|
||||||
|
|
@ -108,17 +108,33 @@ corridor polygon in the v1 design) sound.
|
||||||
|
|
||||||
### Profile deltas matter (measured, same OD pair)
|
### Profile deltas matter (measured, same OD pair)
|
||||||
|
|
||||||
| backend | Lincoln NH → Queens NY |
|
| backend | Lincoln NH → 39-84 46th St, Sunnyside |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Valhalla `auto` | 332 min, 531 km |
|
| Valhalla `auto` | 327 min, 529 km (97 km/h avg) |
|
||||||
| OSRM `car` | 410 min, 514 km |
|
| OSRM stock `car.lua` | 406 min, 511 km (76 km/h avg) |
|
||||||
|
| OSRM US-tuned speed table | 377 min, 526 km (84 km/h avg) |
|
||||||
|
|
||||||
Both avoid Boston (22 km vs 38 km clearance) and both take the
|
All three avoid Boston and take the I-93/90/495/290 corridor — same
|
||||||
I-93/90/495/290 corridor — same route *shape*, different *clocks*.
|
route *shape*, different *clocks*.
|
||||||
Consequences: (a) goldens in `bench/tasks.json` are per
|
|
||||||
backend+profile — re-record (`--record`) after switching; (b) any
|
Why the clocks differ: **the times are the profile's speed assumptions,
|
||||||
user-facing arrival-time math must use one backend consistently per
|
not measurements.** OSRM's stock `car.lua` lists `motorway = 90` km/h
|
||||||
trip and say which.
|
and applies a global `speed_reduction = 0.8` → untagged motorway miles
|
||||||
|
run at ~72 km/h (45 mph). That's a generic/European-flavored default
|
||||||
|
(90 km/h mirrors the European "unsigned road = 90" convention), and US
|
||||||
|
interstates are `maxspeed`-untagged in large stretches, so the default
|
||||||
|
rules. Re-extracting the same data with a US-tuned table
|
||||||
|
(`profiles/car-us.lua`: motorway 135, trunk 130, primary 110, ...
|
||||||
|
through the same 0.8 factor) closes two-thirds of the gap (406 → 377
|
||||||
|
min) and even changes the *route choice* (526 km now — faster
|
||||||
|
motorways make longer interstates win). Valhalla's `auto` is simply
|
||||||
|
calibrated more aggressively (97 km/h average).
|
||||||
|
|
||||||
|
Consequences: (a) goldens in the bench files are per backend+profile —
|
||||||
|
re-record (`--record`) after switching; (b) any user-facing
|
||||||
|
arrival-time math must use one backend consistently per trip and say
|
||||||
|
which; (c) "computed" provenance should carry the profile name,
|
||||||
|
because two computed numbers for the same leg can differ by 20–25%.
|
||||||
|
|
||||||
## Design notes
|
## Design notes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ func liveRouter(t *testing.T) route.Router {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
lincoln = geo.Point{Lat: 44.054, Lon: -71.650}
|
lincoln = geo.Point{Lat: 44.054, Lon: -71.650}
|
||||||
queens = geo.Point{Lat: 40.729, Lon: -73.966}
|
sunnyside = geo.Point{Lat: 40.74707, Lon: -73.9181} // 39-84 46th St, Sunnyside 11104
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLiveDirectRoute(t *testing.T) {
|
func TestLiveDirectRoute(t *testing.T) {
|
||||||
|
|
@ -37,11 +37,11 @@ func TestLiveDirectRoute(t *testing.T) {
|
||||||
r := liveRouter(t)
|
r := liveRouter(t)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
rt, err := r.Route(ctx, route.ProfileDrive, []geo.Point{lincoln, queens})
|
rt, err := r.Route(ctx, route.ProfileDrive, []geo.Point{lincoln, sunnyside})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("route: %v", err)
|
t.Fatalf("route: %v", err)
|
||||||
}
|
}
|
||||||
// Lincoln NH -> Queens NY is a 5.25-5.75h drive (I-93/90/495/290).
|
// Lincoln NH -> Sunnyside is a 5.25-5.75h drive (I-93/90/495/290).
|
||||||
// Anything outside this band means the backend or the dataset is wrong.
|
// Anything outside this band means the backend or the dataset is wrong.
|
||||||
mins := rt.Duration / 60
|
mins := rt.Duration / 60
|
||||||
if mins < 290 || mins > 430 {
|
if mins < 290 || mins > 430 {
|
||||||
|
|
@ -62,7 +62,7 @@ func TestLiveRouteAvoidsBoston(t *testing.T) {
|
||||||
r := liveRouter(t)
|
r := liveRouter(t)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
rt, err := r.Route(ctx, route.ProfileDrive, []geo.Point{lincoln, queens})
|
rt, err := r.Route(ctx, route.ProfileDrive, []geo.Point{lincoln, sunnyside})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("route: %v", err)
|
t.Fatalf("route: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -93,7 +93,7 @@ func TestLiveStopCost(t *testing.T) {
|
||||||
|
|
||||||
cascade := geo.Point{Lat: 42.2767, Lon: -71.806}
|
cascade := geo.Point{Lat: 42.2767, Lon: -71.806}
|
||||||
mtmajor := geo.Point{Lat: 43.642, Lon: -71.156}
|
mtmajor := geo.Point{Lat: 43.642, Lon: -71.156}
|
||||||
pts := []geo.Point{cascade, mtmajor, lincoln, queens}
|
pts := []geo.Point{cascade, mtmajor, lincoln, sunnyside}
|
||||||
m, err := route.BuildMatrix(ctx, r, route.ProfileDrive, pts, 200*time.Millisecond)
|
m, err := route.BuildMatrix(ctx, r, route.ProfileDrive, pts, 200*time.Millisecond)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("matrix: %v", err)
|
t.Fatalf("matrix: %v", err)
|
||||||
|
|
|
||||||
572
router/profiles/car-us.lua
Normal file
572
router/profiles/car-us.lua
Normal file
|
|
@ -0,0 +1,572 @@
|
||||||
|
-- Car profile
|
||||||
|
|
||||||
|
api_version = 4
|
||||||
|
|
||||||
|
Set = require('lib/set')
|
||||||
|
Sequence = require('lib/sequence')
|
||||||
|
Handlers = require("lib/way_handlers")
|
||||||
|
Relations = require("lib/relations")
|
||||||
|
Obstacles = require("lib/obstacles")
|
||||||
|
find_access_tag = require("lib/access").find_access_tag
|
||||||
|
limit = require("lib/maxspeed").limit
|
||||||
|
Utils = require("lib/utils")
|
||||||
|
Measure = require("lib/measure")
|
||||||
|
|
||||||
|
function setup()
|
||||||
|
return {
|
||||||
|
properties = {
|
||||||
|
max_speed_for_map_matching = 180/3.6, -- 180kmph -> m/s
|
||||||
|
-- For routing based on duration, but weighted for preferring certain roads
|
||||||
|
weight_name = 'routability',
|
||||||
|
-- For shortest duration without penalties for accessibility
|
||||||
|
-- weight_name = 'duration',
|
||||||
|
-- For shortest distance without penalties for accessibility
|
||||||
|
-- weight_name = 'distance',
|
||||||
|
process_call_tagless_node = false,
|
||||||
|
u_turn_penalty = 20,
|
||||||
|
continue_straight_at_waypoint = true,
|
||||||
|
use_turn_restrictions = true,
|
||||||
|
left_hand_driving = false,
|
||||||
|
},
|
||||||
|
|
||||||
|
default_mode = mode.driving,
|
||||||
|
default_speed = 10,
|
||||||
|
oneway_handling = true,
|
||||||
|
side_road_multiplier = 0.8,
|
||||||
|
turn_penalty = 7.5,
|
||||||
|
speed_reduction = 0.8,
|
||||||
|
turn_bias = 1.075,
|
||||||
|
cardinal_directions = false,
|
||||||
|
|
||||||
|
-- Penalty multiplier for roads with no lane markings (lane_markings=no)
|
||||||
|
-- Applied to bidirectional roads to prefer roads with clear lane markings
|
||||||
|
lane_markings_penalty = 0.75,
|
||||||
|
|
||||||
|
-- Size of the vehicle, to be limited by physical restriction of the way
|
||||||
|
vehicle_height = 2.0, -- in meters, 2.0m is the height slightly above biggest SUVs
|
||||||
|
vehicle_width = 1.9, -- in meters, ways with narrow tag are considered narrower than 2.2m
|
||||||
|
|
||||||
|
-- Size of the vehicle, to be limited mostly by legal restriction of the way
|
||||||
|
vehicle_length = 4.8, -- in meters, 4.8m is the length of large or family car
|
||||||
|
vehicle_weight = 2000, -- in kilograms
|
||||||
|
|
||||||
|
-- Optional: upper limit for all speeds (e.g., 87 for trucks)
|
||||||
|
-- When set, no derived speed will exceed this value
|
||||||
|
-- When nil (default), no additional capping is applied
|
||||||
|
vehicle_max_speed = nil, -- in km/h
|
||||||
|
|
||||||
|
-- a list of suffixes to suppress in name change instructions. The suffixes also include common substrings of each other
|
||||||
|
suffix_list = {
|
||||||
|
'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East', 'Nor', 'Sou', 'We', 'Ea'
|
||||||
|
},
|
||||||
|
|
||||||
|
barrier_whitelist = Set {
|
||||||
|
'cattle_grid',
|
||||||
|
'border_control',
|
||||||
|
'toll_booth',
|
||||||
|
'sally_port',
|
||||||
|
'no',
|
||||||
|
'entrance',
|
||||||
|
'height_restrictor',
|
||||||
|
'arch'
|
||||||
|
},
|
||||||
|
|
||||||
|
access_tag_whitelist = Set {
|
||||||
|
'yes',
|
||||||
|
'motorcar',
|
||||||
|
'motor_vehicle',
|
||||||
|
'vehicle',
|
||||||
|
'permissive',
|
||||||
|
'designated',
|
||||||
|
'hov'
|
||||||
|
},
|
||||||
|
|
||||||
|
access_tag_blacklist = Set {
|
||||||
|
'no',
|
||||||
|
'agricultural',
|
||||||
|
'forestry',
|
||||||
|
'emergency',
|
||||||
|
'psv',
|
||||||
|
'taxi', -- sub class of psv
|
||||||
|
'share_taxi', -- sub class of psv
|
||||||
|
'minibus', -- sub class of psv
|
||||||
|
'bus', -- sub class of psv
|
||||||
|
'customers',
|
||||||
|
'private',
|
||||||
|
'delivery',
|
||||||
|
'destination'
|
||||||
|
},
|
||||||
|
|
||||||
|
-- tags disallow access to in combination with highway=service
|
||||||
|
service_access_tag_blacklist = Set {
|
||||||
|
'private'
|
||||||
|
},
|
||||||
|
|
||||||
|
restricted_access_tag_list = Set {
|
||||||
|
'private',
|
||||||
|
'delivery',
|
||||||
|
'destination',
|
||||||
|
'customers',
|
||||||
|
},
|
||||||
|
|
||||||
|
access_tags_hierarchy = Sequence {
|
||||||
|
'motorcar',
|
||||||
|
'motor_vehicle',
|
||||||
|
'vehicle',
|
||||||
|
'access'
|
||||||
|
},
|
||||||
|
|
||||||
|
service_tag_forbidden = Set {
|
||||||
|
'emergency_access'
|
||||||
|
},
|
||||||
|
|
||||||
|
restrictions = Sequence {
|
||||||
|
'motorcar',
|
||||||
|
'motor_vehicle',
|
||||||
|
'vehicle'
|
||||||
|
},
|
||||||
|
|
||||||
|
classes = Sequence {
|
||||||
|
'toll', 'motorway', 'ferry', 'restricted', 'tunnel'
|
||||||
|
},
|
||||||
|
|
||||||
|
-- classes to support for exclude flags
|
||||||
|
excludable = Sequence {
|
||||||
|
Set {'toll'},
|
||||||
|
Set {'motorway'},
|
||||||
|
Set {'ferry'}
|
||||||
|
},
|
||||||
|
|
||||||
|
avoid = Set {
|
||||||
|
'area',
|
||||||
|
-- 'toll', -- uncomment this to avoid tolls
|
||||||
|
'reversible',
|
||||||
|
'impassable',
|
||||||
|
'hov_lanes',
|
||||||
|
'steps',
|
||||||
|
'construction',
|
||||||
|
'proposed'
|
||||||
|
},
|
||||||
|
|
||||||
|
speeds = Sequence {
|
||||||
|
highway = {
|
||||||
|
motorway = 135, -- US-tuned (effective x speed_reduction 0.8)
|
||||||
|
motorway_link = 75,
|
||||||
|
trunk = 130,
|
||||||
|
trunk_link = 70,
|
||||||
|
primary = 110,
|
||||||
|
primary_link = 60,
|
||||||
|
secondary = 90,
|
||||||
|
secondary_link = 55,
|
||||||
|
tertiary = 70,
|
||||||
|
tertiary_link = 45,
|
||||||
|
unclassified = 55,
|
||||||
|
residential = 45,
|
||||||
|
living_street = 15,
|
||||||
|
service = 20,
|
||||||
|
-- winter highway types (OSM highway=winter_road / highway=ice_road)
|
||||||
|
winter_road = 20,
|
||||||
|
ice_road = 15
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
service_penalties = {
|
||||||
|
alley = 0.5,
|
||||||
|
parking = 0.5,
|
||||||
|
parking_aisle = 0.5,
|
||||||
|
driveway = 0.5,
|
||||||
|
["drive-through"] = 0.5,
|
||||||
|
["drive-thru"] = 0.5
|
||||||
|
},
|
||||||
|
|
||||||
|
barrier_penalties = {
|
||||||
|
gate = 60,
|
||||||
|
lift_gate = 60,
|
||||||
|
},
|
||||||
|
|
||||||
|
restricted_highway_whitelist = Set {
|
||||||
|
'motorway',
|
||||||
|
'motorway_link',
|
||||||
|
'trunk',
|
||||||
|
'trunk_link',
|
||||||
|
'primary',
|
||||||
|
'primary_link',
|
||||||
|
'secondary',
|
||||||
|
'secondary_link',
|
||||||
|
'tertiary',
|
||||||
|
'tertiary_link',
|
||||||
|
'residential',
|
||||||
|
'living_street',
|
||||||
|
'unclassified',
|
||||||
|
'service'
|
||||||
|
},
|
||||||
|
|
||||||
|
construction_whitelist = Set {
|
||||||
|
'no',
|
||||||
|
'widening',
|
||||||
|
'minor',
|
||||||
|
},
|
||||||
|
|
||||||
|
route_speeds = {
|
||||||
|
ferry = 5,
|
||||||
|
shuttle_train = 10
|
||||||
|
},
|
||||||
|
|
||||||
|
bridge_speeds = {
|
||||||
|
movable = 5
|
||||||
|
},
|
||||||
|
|
||||||
|
-- surface/trackype/smoothness
|
||||||
|
-- values were estimated from looking at the photos at the relevant wiki pages
|
||||||
|
|
||||||
|
-- max speed for surfaces
|
||||||
|
surface_speeds = {
|
||||||
|
asphalt = nil, -- nil mean no limit. removing the line has the same effect
|
||||||
|
concrete = nil,
|
||||||
|
["concrete:plates"] = nil,
|
||||||
|
["concrete:lanes"] = nil,
|
||||||
|
paved = nil,
|
||||||
|
|
||||||
|
cement = 80,
|
||||||
|
compacted = 80,
|
||||||
|
fine_gravel = 80,
|
||||||
|
|
||||||
|
paving_stones = 60,
|
||||||
|
metal = 60,
|
||||||
|
bricks = 60,
|
||||||
|
|
||||||
|
grass = 40,
|
||||||
|
wood = 40,
|
||||||
|
sett = 40,
|
||||||
|
grass_paver = 40,
|
||||||
|
gravel = 40,
|
||||||
|
unpaved = 40,
|
||||||
|
ground = 40,
|
||||||
|
dirt = 40,
|
||||||
|
pebblestone = 40,
|
||||||
|
tartan = 40,
|
||||||
|
|
||||||
|
cobblestone = 30,
|
||||||
|
clay = 30,
|
||||||
|
|
||||||
|
earth = 20,
|
||||||
|
stone = 20,
|
||||||
|
rocky = 20,
|
||||||
|
sand = 20,
|
||||||
|
|
||||||
|
mud = 10,
|
||||||
|
|
||||||
|
-- winter surfaces (OSM surface=ice / surface=snow)
|
||||||
|
ice = 20,
|
||||||
|
snow = 30
|
||||||
|
},
|
||||||
|
|
||||||
|
-- max speed for tracktypes
|
||||||
|
tracktype_speeds = {
|
||||||
|
grade1 = 60,
|
||||||
|
grade2 = 40,
|
||||||
|
grade3 = 30,
|
||||||
|
grade4 = 25,
|
||||||
|
grade5 = 20
|
||||||
|
},
|
||||||
|
|
||||||
|
-- max speed for smoothnesses
|
||||||
|
smoothness_speeds = {
|
||||||
|
intermediate = 80,
|
||||||
|
bad = 40,
|
||||||
|
very_bad = 20,
|
||||||
|
horrible = 10,
|
||||||
|
very_horrible = 5,
|
||||||
|
impassable = 0
|
||||||
|
},
|
||||||
|
|
||||||
|
-- http://wiki.openstreetmap.org/wiki/Speed_limits
|
||||||
|
maxspeed_table_default = {
|
||||||
|
urban = 50,
|
||||||
|
rural = 90,
|
||||||
|
trunk = 110,
|
||||||
|
motorway = 130
|
||||||
|
},
|
||||||
|
|
||||||
|
-- List only exceptions
|
||||||
|
maxspeed_table = {
|
||||||
|
["at:rural"] = 100,
|
||||||
|
["at:trunk"] = 100,
|
||||||
|
["ar:urban"] = 40,
|
||||||
|
["ar:rural"] = 110,
|
||||||
|
["be:motorway"] = 120,
|
||||||
|
["be-bru:rural"] = 70,
|
||||||
|
["be-bru:urban"] = 30,
|
||||||
|
["be-vlg:rural"] = 70,
|
||||||
|
["bg:motorway"] = 140,
|
||||||
|
["by:urban"] = 60,
|
||||||
|
["by:motorway"] = 110,
|
||||||
|
["ca-on:rural"] = 80,
|
||||||
|
["ch:rural"] = 80,
|
||||||
|
["ch:trunk"] = 100,
|
||||||
|
["ch:motorway"] = 120,
|
||||||
|
["de:living_street"] = 7,
|
||||||
|
["de:rural"] = 100,
|
||||||
|
["de:motorway"] = 0,
|
||||||
|
["dk:rural"] = 80,
|
||||||
|
["es:trunk"] = 90,
|
||||||
|
["fr:rural"] = 80,
|
||||||
|
["gb:nsl_single"] = (60*1609)/1000,
|
||||||
|
["gb:nsl_dual"] = (70*1609)/1000,
|
||||||
|
["gb:motorway"] = (70*1609)/1000,
|
||||||
|
["lv:living_street"] = 20,
|
||||||
|
["nl:rural"] = 80,
|
||||||
|
["nl:trunk"] = 100,
|
||||||
|
['no:rural'] = 80,
|
||||||
|
['no:motorway'] = 110,
|
||||||
|
['ph:urban'] = 40,
|
||||||
|
['ph:rural'] = 80,
|
||||||
|
['ph:motorway'] = 100,
|
||||||
|
['pl:rural'] = 100,
|
||||||
|
['pl:expressway'] = 120,
|
||||||
|
['pl:motorway'] = 140,
|
||||||
|
["ro:trunk"] = 100,
|
||||||
|
["ru:living_street"] = 20,
|
||||||
|
["ru:urban"] = 60,
|
||||||
|
["ru:motorway"] = 110,
|
||||||
|
["uk:nsl_single"] = (60*1609)/1000,
|
||||||
|
["uk:nsl_dual"] = (70*1609)/1000,
|
||||||
|
["uk:motorway"] = (70*1609)/1000,
|
||||||
|
['za:urban'] = 60,
|
||||||
|
['za:rural'] = 100,
|
||||||
|
["none"] = 140
|
||||||
|
},
|
||||||
|
|
||||||
|
relation_types = Sequence {
|
||||||
|
"route"
|
||||||
|
},
|
||||||
|
|
||||||
|
-- classify highway tags when necessary for turn weights
|
||||||
|
highway_turn_classification = {
|
||||||
|
},
|
||||||
|
|
||||||
|
-- classify access tags when necessary for turn weights
|
||||||
|
access_turn_classification = {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function process_node(profile, node, result, relations)
|
||||||
|
-- parse access and barrier tags
|
||||||
|
local access = find_access_tag(node, profile.access_tags_hierarchy)
|
||||||
|
if access then
|
||||||
|
if profile.access_tag_blacklist[access] and not profile.restricted_access_tag_list[access] then
|
||||||
|
obstacle_map:add(node, Obstacle.new(obstacle_type.barrier))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local barrier = node:get_value_by_key("barrier")
|
||||||
|
if barrier then
|
||||||
|
-- check height restriction barriers
|
||||||
|
local restricted_by_height = false
|
||||||
|
if barrier == 'height_restrictor' then
|
||||||
|
local maxheight = Measure.get_max_height(node:get_value_by_key("maxheight"), node)
|
||||||
|
restricted_by_height = maxheight and maxheight < profile.vehicle_height
|
||||||
|
end
|
||||||
|
|
||||||
|
-- make an exception for rising bollard barriers
|
||||||
|
local bollard = node:get_value_by_key("bollard")
|
||||||
|
local rising_bollard = bollard and "rising" == bollard
|
||||||
|
|
||||||
|
-- make an exception for lowered/flat barrier=kerb
|
||||||
|
-- and incorrect tagging of highway crossing kerb as highway barrier
|
||||||
|
local kerb = node:get_value_by_key("kerb")
|
||||||
|
local highway = node:get_value_by_key("highway")
|
||||||
|
local flat_kerb = kerb and ("lowered" == kerb or "flush" == kerb)
|
||||||
|
local highway_crossing_kerb = barrier == "kerb" and highway and highway == "crossing"
|
||||||
|
|
||||||
|
-- make an exception for fence with sensory=audible/audio (virtual livestock fences)
|
||||||
|
local sensory = node:get_value_by_key("sensory")
|
||||||
|
local audible_fence = barrier == "fence" and sensory and (sensory == "audible" or sensory == "audio")
|
||||||
|
|
||||||
|
-- check if barrier has a configurable penalty (e.g., gates)
|
||||||
|
local barrier_penalty = profile.barrier_penalties[barrier]
|
||||||
|
|
||||||
|
if not profile.barrier_whitelist[barrier]
|
||||||
|
and not rising_bollard
|
||||||
|
and not flat_kerb
|
||||||
|
and not highway_crossing_kerb
|
||||||
|
and not audible_fence
|
||||||
|
and not barrier_penalty
|
||||||
|
or restricted_by_height then
|
||||||
|
obstacle_map:add(node, Obstacle.new(obstacle_type.barrier))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- apply configurable penalty to gates/lift_gates
|
||||||
|
if barrier_penalty then
|
||||||
|
obstacle_map:add(node, Obstacle.new(obstacle_type.gate,
|
||||||
|
obstacle_direction.both, barrier_penalty, 0))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Obstacles.process_node(profile, node)
|
||||||
|
end
|
||||||
|
|
||||||
|
function process_way(profile, way, result, relations)
|
||||||
|
-- the intial filtering of ways based on presence of tags
|
||||||
|
-- affects processing times significantly, because all ways
|
||||||
|
-- have to be checked.
|
||||||
|
-- to increase performance, prefetching and intial tag check
|
||||||
|
-- is done in directly instead of via a handler.
|
||||||
|
|
||||||
|
-- in general we should try to abort as soon as
|
||||||
|
-- possible if the way is not routable, to avoid doing
|
||||||
|
-- unnecessary work. this implies we should check things that
|
||||||
|
-- commonly forbids access early, and handle edge cases later.
|
||||||
|
|
||||||
|
-- data table for storing intermediate values during processing
|
||||||
|
local data = {
|
||||||
|
-- prefetch tags
|
||||||
|
highway = way:get_value_by_key('highway'),
|
||||||
|
bridge = way:get_value_by_key('bridge'),
|
||||||
|
route = way:get_value_by_key('route')
|
||||||
|
}
|
||||||
|
|
||||||
|
-- perform an quick initial check and abort if the way is
|
||||||
|
-- obviously not routable.
|
||||||
|
-- highway or route tags must be in data table, bridge is optional
|
||||||
|
if (not data.highway or data.highway == '') and
|
||||||
|
(not data.route or data.route == '')
|
||||||
|
then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
handlers = Sequence {
|
||||||
|
-- set the default mode for this profile. if can be changed later
|
||||||
|
-- in case it turns we're e.g. on a ferry
|
||||||
|
WayHandlers.default_mode,
|
||||||
|
|
||||||
|
-- check various tags that could indicate that the way is not
|
||||||
|
-- routable. this includes things like status=impassable,
|
||||||
|
-- toll=yes and oneway=reversible
|
||||||
|
WayHandlers.blocked_ways,
|
||||||
|
WayHandlers.avoid_ways,
|
||||||
|
WayHandlers.handle_height,
|
||||||
|
WayHandlers.handle_width,
|
||||||
|
WayHandlers.handle_length,
|
||||||
|
WayHandlers.handle_weight,
|
||||||
|
|
||||||
|
-- determine access status by checking our hierarchy of
|
||||||
|
-- access tags, e.g: motorcar, motor_vehicle, vehicle
|
||||||
|
WayHandlers.access,
|
||||||
|
|
||||||
|
-- check whether forward/backward directions are routable
|
||||||
|
WayHandlers.oneway,
|
||||||
|
|
||||||
|
-- check a road's destination
|
||||||
|
WayHandlers.destinations,
|
||||||
|
|
||||||
|
-- check whether we're using a special transport mode
|
||||||
|
WayHandlers.ferries,
|
||||||
|
WayHandlers.movables,
|
||||||
|
|
||||||
|
-- handle service road restrictions
|
||||||
|
WayHandlers.service,
|
||||||
|
|
||||||
|
-- handle hov
|
||||||
|
WayHandlers.hov,
|
||||||
|
|
||||||
|
-- compute speed taking into account way type, maxspeed tags, etc.
|
||||||
|
WayHandlers.speed,
|
||||||
|
WayHandlers.maxspeed,
|
||||||
|
WayHandlers.surface,
|
||||||
|
|
||||||
|
-- apply vehicle-specific maximum speed cap before calculating rates
|
||||||
|
WayHandlers.vehicle_speed_cap,
|
||||||
|
|
||||||
|
WayHandlers.penalties,
|
||||||
|
|
||||||
|
-- compute class labels
|
||||||
|
WayHandlers.classes,
|
||||||
|
|
||||||
|
-- handle turn lanes and road classification, used for guidance
|
||||||
|
WayHandlers.turn_lanes,
|
||||||
|
WayHandlers.classification,
|
||||||
|
|
||||||
|
-- handle various other flags
|
||||||
|
WayHandlers.roundabouts,
|
||||||
|
WayHandlers.startpoint,
|
||||||
|
WayHandlers.driving_side,
|
||||||
|
|
||||||
|
-- set name, ref and pronunciation
|
||||||
|
WayHandlers.names,
|
||||||
|
|
||||||
|
-- set weight properties of the way
|
||||||
|
WayHandlers.weights,
|
||||||
|
|
||||||
|
-- set classification of ways relevant for turns
|
||||||
|
WayHandlers.way_classification_for_turn
|
||||||
|
}
|
||||||
|
|
||||||
|
WayHandlers.run(profile, way, result, data, handlers, relations)
|
||||||
|
|
||||||
|
if profile.cardinal_directions then
|
||||||
|
Relations.process_way_refs(way, relations, result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function process_turn(profile, turn)
|
||||||
|
-- Use a sigmoid function to return a penalty that maxes out at turn_penalty
|
||||||
|
-- over the space of 0-180 degrees. Values here were chosen by fitting
|
||||||
|
-- the function to some turn penalty samples from real driving.
|
||||||
|
local turn_penalty = profile.turn_penalty
|
||||||
|
local turn_bias = turn.is_left_hand_driving and 1. / profile.turn_bias or profile.turn_bias
|
||||||
|
|
||||||
|
for _, obs in pairs(obstacle_map:get(turn.from, turn.via)) do
|
||||||
|
-- disregard a minor stop if entering by the major road
|
||||||
|
-- rationale: if a stop sign is tagged at the center of the intersection with stop=minor
|
||||||
|
-- it should only penalize the minor roads entering the intersection
|
||||||
|
if obs.type == obstacle_type.stop_minor and not Obstacles.entering_by_minor_road(turn) then
|
||||||
|
goto skip
|
||||||
|
end
|
||||||
|
-- heuristic to infer the direction of a stop without an explicit direction tag
|
||||||
|
-- rationale: a stop sign should not be placed farther than 20m from the intersection
|
||||||
|
if turn.number_of_roads == 2
|
||||||
|
and obs.type == obstacle_type.stop
|
||||||
|
and obs.direction == obstacle_direction.none
|
||||||
|
and turn.source_road.distance < 20
|
||||||
|
and turn.target_road.distance > 20 then
|
||||||
|
goto skip
|
||||||
|
end
|
||||||
|
turn.duration = turn.duration + obs.duration
|
||||||
|
::skip::
|
||||||
|
end
|
||||||
|
|
||||||
|
if turn.number_of_roads > 2 or turn.source_mode ~= turn.target_mode or turn.is_u_turn then
|
||||||
|
if turn.angle >= 0 then
|
||||||
|
turn.duration = turn.duration + turn_penalty / (1 + math.exp( -((13 / turn_bias) * turn.angle/180 - 6.5*turn_bias)))
|
||||||
|
else
|
||||||
|
turn.duration = turn.duration + turn_penalty / (1 + math.exp( -((13 * turn_bias) * -turn.angle/180 - 6.5/turn_bias)))
|
||||||
|
end
|
||||||
|
|
||||||
|
if turn.is_u_turn then
|
||||||
|
turn.duration = turn.duration + profile.properties.u_turn_penalty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- for distance based routing we don't want to have penalties based on turn angle
|
||||||
|
if profile.properties.weight_name == 'distance' then
|
||||||
|
turn.weight = 0
|
||||||
|
else
|
||||||
|
turn.weight = turn.duration
|
||||||
|
end
|
||||||
|
|
||||||
|
if profile.properties.weight_name == 'routability' then
|
||||||
|
-- penalize turns from non-local access only segments onto local access only tags
|
||||||
|
if not turn.source_restricted and turn.target_restricted then
|
||||||
|
turn.weight = constants.max_turn_weight
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
setup = setup,
|
||||||
|
process_way = process_way,
|
||||||
|
process_node = process_node,
|
||||||
|
process_turn = process_turn
|
||||||
|
}
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
# conan: bzip2, lua 5.2 (static), oneTBB, boost (b2, with hand-rolled
|
# conan: bzip2, lua 5.2 (static), oneTBB, boost (b2, with hand-rolled
|
||||||
# CMake config files — boost release tarballs ship no CMake support).
|
# CMake config files — boost release tarballs ship no CMake support).
|
||||||
#
|
#
|
||||||
# Artifacts: $W (default /tmp/osm-build), installed into $W/prefix.
|
# Artifacts: $W (default $HOME/osm-build), installed into $W/prefix.
|
||||||
# Idempotent: each dep is skipped when its .done-<name> marker exists.
|
# Idempotent: each dep is skipped when its .done-<name> marker exists.
|
||||||
set -uo pipefail
|
set -uo pipefail
|
||||||
W="${W:-/tmp/osm-build}"
|
W="${W:-$HOME/osm-build}"
|
||||||
P="$W/prefix"
|
P="$W/prefix"
|
||||||
mkdir -p "$P/include" "$P/lib" "$W"
|
mkdir -p "$P/include" "$P/lib" "$W"
|
||||||
log() { echo "[$(date +%T)] $*"; }
|
log() { echo "[$(date +%T)] $*"; }
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,12 @@
|
||||||
# Usage: scripts/setup-osrm.sh # everything, then serve
|
# Usage: scripts/setup-osrm.sh # everything, then serve
|
||||||
# scripts/setup-osrm.sh --no-serve # build + extract, don't serve
|
# scripts/setup-osrm.sh --no-serve # build + extract, don't serve
|
||||||
#
|
#
|
||||||
# NOTE: /tmp is wiped on reboot. For a persistent install set W to a
|
# Artifacts live in $W (default: $HOME/osm-build — durable; the extract
|
||||||
# durable dir (and the extract's ~8 GB lives under $W/data).
|
# is ~8 GB under $W/data). PBFs are in ../../osm/ (~1.1 GB, gitignored).
|
||||||
#
|
|
||||||
# PBFs are pre-downloaded in ../../osm/ (see router/README.md); ~1.1 GB.
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
cd "$(dirname "$0")"
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
W="${W:-/tmp/osm-build}"
|
W="${W:-$HOME/osm-build}"
|
||||||
P="$W/prefix"
|
P="$W/prefix"
|
||||||
OSM_DIR="$(cd ../.. && pwd)/osm"
|
OSM_DIR="$(cd ../.. && pwd)/osm"
|
||||||
DATA_DIR="${DATA_DIR:-$W/data}"
|
DATA_DIR="${DATA_DIR:-$W/data}"
|
||||||
|
|
@ -29,6 +27,10 @@ step() { echo; echo "=== $1"; }
|
||||||
step "1/6 dependencies (bzip2, lua, tbb, boost, osmium)"
|
step "1/6 dependencies (bzip2, lua, tbb, boost, osmium)"
|
||||||
bash deps.sh
|
bash deps.sh
|
||||||
|
|
||||||
|
# The built OSRM binaries carry an RPATH baked in at configure time;
|
||||||
|
# if $W ever moves, this keeps them finding their TBB/boost libs.
|
||||||
|
export LD_LIBRARY_PATH="$P/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||||
|
|
||||||
step "2/6 OSRM 26.4.1"
|
step "2/6 OSRM 26.4.1"
|
||||||
if [ ! -d "$OSRM_SRC" ]; then
|
if [ ! -d "$OSRM_SRC" ]; then
|
||||||
curl -sL -o "$W/osrm.tar.gz" https://github.com/Project-OSRM/osrm-backend/archive/refs/tags/v26.4.1.tar.gz
|
curl -sL -o "$W/osrm.tar.gz" https://github.com/Project-OSRM/osrm-backend/archive/refs/tags/v26.4.1.tar.gz
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user