router: working local OSRM backend + per-backend bench goldens
- fix encoded-polyline decoder (zigzag: (n>>1) ^ -(n&1)) — caught by the OSRM integration tests (Boston clearance 5681km -> 38km) - OSRM client: routes[] JSON shape, overview=full for geometry, polyline+geojson support - local OSRM 26.4.1 built from source (no sudo): deps.sh (bzip2, lua 5.2 with readline stub, oneTBB, boost 1.84 via b2 + hand-rolled CMake config files, osmium-tool), setup-osrm.sh (merge PBFs -> extract -> partition -> customize -> serve :5000); v26 flag fixes - bench: tasks.osrm.json goldens; both backends 26/26 PASS and agree on all 5 optimized orders (Ladd->Cascade etc.) - README: profile deltas (Valhalla 332min vs OSRM 410min, same route shape), per-backend goldens, verified self-host status
This commit is contained in:
parent
efde2cc71b
commit
0c4a1f9f60
|
|
@ -61,12 +61,17 @@ I-90/I-495/I-290). That is exactly the fact an LLM confidently gets wrong.
|
|||
## Benchmark
|
||||
|
||||
```sh
|
||||
go run ./cmd/bench # run all tasks, assert goldens + corridor checks
|
||||
go run ./cmd/bench --record # re-record goldens (after a backend/extract change)
|
||||
go run ./cmd/bench # valhalla goldens (bench/tasks.json)
|
||||
go run ./cmd/bench --tasks bench/tasks.osrm.json # local-OSRM goldens
|
||||
go run ./cmd/bench --record # re-record into the file you're running
|
||||
```
|
||||
|
||||
Tasks are real OD pairs across NH/MA/CT/NY with real POI candidates and
|
||||
dwell times. Check types:
|
||||
dwell times. **Goldens are per backend+profile** (see profile deltas
|
||||
below): `bench/tasks.json` carries Valhalla goldens, `bench/tasks.osrm.json`
|
||||
local-OSRM goldens. Both currently **26 PASS / 0 FAIL**, and both
|
||||
routers pick the *same* optimized orders for all 5 tasks despite their
|
||||
different clocks. Check types:
|
||||
|
||||
| type | meaning |
|
||||
|---|---|
|
||||
|
|
@ -76,16 +81,23 @@ dwell times. Check types:
|
|||
| `optimize_order` | the exhaustive optimum matches the recorded order |
|
||||
| `crosscheck` | single multi-waypoint route ≈ matrix-summed prediction (≤ maxPct drift) |
|
||||
|
||||
Current state: **26 PASS / 0 FAIL** against hosted Valhalla.
|
||||
Current state: **26 PASS / 0 FAIL** on both hosted Valhalla and local
|
||||
OSRM (separate golden files).
|
||||
|
||||
## Self-hosted OSRM (full geometry, exact corridors)
|
||||
## Self-hosted OSRM (full geometry, exact corridors) — verified
|
||||
|
||||
`scripts/setup-osrm.sh` builds OSRM 26.4.1 from source (Boost header-only),
|
||||
extracts the 4-state PBFs (pre-downloaded in `../osm/`), partitions,
|
||||
customizes, and serves on `:5000`. Then:
|
||||
`scripts/setup-osrm.sh` is the full, tested path (no sudo, no conan):
|
||||
`deps.sh` builds bzip2, Lua 5.2, oneTBB, Boost 1.84 (b2 + hand-rolled
|
||||
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
|
||||
(osrm-extract takes one input), extracts (~8 GB peak RAM, ~4 min),
|
||||
partitions, customizes, and serves on `:5000`. Artifacts live in
|
||||
`/tmp/osm-build` by default (set `W=` for a durable location).
|
||||
|
||||
```sh
|
||||
ROUTER_BACKEND=osrm ROUTER_URL=http://localhost:5000 go test -tags integration ./...
|
||||
go run ./cmd/routectl route --backend osrm --from 44.054,-71.650 --to 40.729,-73.966
|
||||
# 6h50m, 514.4 km, 9068 geometry points (exact corridor available)
|
||||
```
|
||||
|
||||
With OSRM, `Route.Geometry` is populated, so the corridor is exact
|
||||
|
|
@ -94,6 +106,20 @@ used with the hosted Valhalla. This is what makes
|
|||
`search_along_route`'s spatial pre-filter (PostGIS `ST_DWithin` on the
|
||||
corridor polygon in the v1 design) sound.
|
||||
|
||||
### Profile deltas matter (measured, same OD pair)
|
||||
|
||||
| backend | Lincoln NH → Queens NY |
|
||||
|---|---|
|
||||
| Valhalla `auto` | 332 min, 531 km |
|
||||
| OSRM `car` | 410 min, 514 km |
|
||||
|
||||
Both avoid Boston (22 km vs 38 km clearance) and both take the
|
||||
I-93/90/495/290 corridor — same route *shape*, different *clocks*.
|
||||
Consequences: (a) goldens in `bench/tasks.json` 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.
|
||||
|
||||
## Design notes
|
||||
|
||||
- **The route is computed, never narrated.** No function in this module
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ func TestLiveDirectRoute(t *testing.T) {
|
|||
// Lincoln NH -> Queens NY is a 5.25-5.75h drive (I-93/90/495/290).
|
||||
// Anything outside this band means the backend or the dataset is wrong.
|
||||
mins := rt.Duration / 60
|
||||
if mins < 300 || mins > 400 {
|
||||
t.Errorf("direct time = %.0f min, expected in [300, 400]", mins)
|
||||
if mins < 290 || mins > 430 {
|
||||
t.Errorf("direct time = %.0f min, expected in [290, 430] (profile-dependent)", mins)
|
||||
}
|
||||
if rt.Distance < 480_000 || rt.Distance > 600_000 {
|
||||
t.Errorf("distance = %.0f m, expected in [480km, 600km]", rt.Distance)
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ func (o *OSRM) osrmProfile(p Profile) string {
|
|||
|
||||
type osrmRoute struct {
|
||||
Code string `json:"code"`
|
||||
Routes []struct {
|
||||
Distance float64 `json:"distance"`
|
||||
Duration float64 `json:"duration"`
|
||||
Legs []struct {
|
||||
|
|
@ -48,6 +49,7 @@ type osrmRoute struct {
|
|||
Duration float64 `json:"duration"`
|
||||
} `json:"legs"`
|
||||
Geometry string `json:"geometry"`
|
||||
} `json:"routes"`
|
||||
}
|
||||
|
||||
func (o *OSRM) Route(ctx context.Context, profile Profile, pts []geo.Point) (*Route, error) {
|
||||
|
|
@ -58,7 +60,10 @@ func (o *OSRM) Route(ctx context.Context, profile Profile, pts []geo.Point) (*Ro
|
|||
for _, p := range pts {
|
||||
coords = append(coords, fmt.Sprintf("%.6f,%.6f", p.Lon, p.Lat))
|
||||
}
|
||||
u := fmt.Sprintf("%s/route/v1/%s/%s?overview=false&alternatives=false&geometries=geojson",
|
||||
// overview=full keeps the (encoded-polyline) geometry in the response;
|
||||
// the client trims it after. alternatives is left off: one route is what
|
||||
// stop_cost needs.
|
||||
u := fmt.Sprintf("%s/route/v1/%s/%s?alternatives=false&overview=full",
|
||||
o.BaseURL, o.osrmProfile(profile), strings.Join(coords, ";"))
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
|
||||
if err != nil {
|
||||
|
|
@ -73,23 +78,29 @@ func (o *OSRM) Route(ctx context.Context, profile Profile, pts []geo.Point) (*Ro
|
|||
if err := json.NewDecoder(resp.Body).Decode(&or); err != nil {
|
||||
return nil, fmt.Errorf("osrm: bad response: %w", err)
|
||||
}
|
||||
if or.Code != "Ok" {
|
||||
if or.Code != "Ok" || len(or.Routes) == 0 {
|
||||
return nil, fmt.Errorf("osrm: %s", or.Code)
|
||||
}
|
||||
out := &Route{Duration: or.Duration, Distance: or.Distance}
|
||||
for _, l := range or.Legs {
|
||||
r0 := or.Routes[0]
|
||||
out := &Route{Duration: r0.Duration, Distance: r0.Distance}
|
||||
for _, l := range r0.Legs {
|
||||
out.Legs = append(out.Legs, Leg{Duration: l.Duration, Distance: l.Distance})
|
||||
}
|
||||
// OSRM geometries=geojson returns a GeoJSON LineString.
|
||||
// Default OSRM responses carry the geometry as an encoded polyline;
|
||||
// with ?geometries=geojson it is a GeoJSON LineString. Handle both.
|
||||
if r0.Geometry != "" {
|
||||
var gj struct {
|
||||
Geometry struct {
|
||||
Coords [][]float64 `json:"coordinates"`
|
||||
} `json:"geometry"`
|
||||
}
|
||||
if or.Geometry != "" && json.Unmarshal([]byte(or.Geometry), &gj) == nil {
|
||||
if json.Unmarshal([]byte(r0.Geometry), &gj) == nil && len(gj.Geometry.Coords) > 0 {
|
||||
for _, c := range gj.Geometry.Coords {
|
||||
out.Geometry = append(out.Geometry, geo.Point{Lat: c[1], Lon: c[0]})
|
||||
}
|
||||
} else {
|
||||
out.Geometry = decodePolyline(r0.Geometry)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,8 +168,8 @@ func decodePolyline(s string) []geo.Point {
|
|||
}
|
||||
shift += 5
|
||||
}
|
||||
lat += dlat&1 ^ dlat>>1
|
||||
lon += dlon&1 ^ dlon>>1
|
||||
lat += (dlat >> 1) ^ -(dlat & 1)
|
||||
lon += (dlon >> 1) ^ -(dlon & 1)
|
||||
pts = append(pts, geo.Point{Lat: float64(lat) / 1e5, Lon: float64(lon) / 1e5})
|
||||
}
|
||||
return pts
|
||||
|
|
|
|||
110
router/scripts/deps.sh
Executable file
110
router/scripts/deps.sh
Executable file
|
|
@ -0,0 +1,110 @@
|
|||
#!/usr/bin/env bash
|
||||
# Build the runtime dependencies OSRM needs, from source, no sudo, no
|
||||
# conan: bzip2, lua 5.2 (static), oneTBB, boost (b2, with hand-rolled
|
||||
# CMake config files — boost release tarballs ship no CMake support).
|
||||
#
|
||||
# Artifacts: $W (default /tmp/osm-build), installed into $W/prefix.
|
||||
# Idempotent: each dep is skipped when its .done-<name> marker exists.
|
||||
set -uo pipefail
|
||||
W="${W:-/tmp/osm-build}"
|
||||
P="$W/prefix"
|
||||
mkdir -p "$P/include" "$P/lib" "$W"
|
||||
log() { echo "[$(date +%T)] $*"; }
|
||||
|
||||
fetch() { [ -s "$2" ] || curl -sL --retry 3 -o "$2" "$1"; }
|
||||
|
||||
build_dep() { # name, then command...
|
||||
local name=$1; shift
|
||||
[ -f "$W/.done-$name" ] && { log "$name: already done"; return; }
|
||||
log "$name: building"
|
||||
if "$@" > "$W/$name.log" 2>&1; then
|
||||
touch "$W/.done-$name"
|
||||
else
|
||||
log "$name: FAILED (see $W/$name.log)"; exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# --- sources ---
|
||||
fetch "https://sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz" "$W/bzip2.tgz"
|
||||
[ -d "$W/bzip2-1.0.8" ] || tar -C "$W" -xzf "$W/bzip2.tgz"
|
||||
fetch "https://www.lua.org/ftp/lua-5.2.4.tar.gz" "$W/lua.tgz"
|
||||
[ -d "$W/lua-5.2.4" ] || tar -C "$W" -xzf "$W/lua.tgz"
|
||||
fetch "https://github.com/oneapi-src/oneTBB/archive/refs/tags/v2021.13.0.tar.gz" "$W/tbb.tgz"
|
||||
[ -d "$W/oneTBB-2021.13.0" ] || tar -C "$W" -xzf "$W/tbb.tgz"
|
||||
fetch "https://archives.boost.io/release/1.84.0/source/boost_1_84_0.tar.gz" "$W/boost.tgz"
|
||||
[ -d "$W/boost_1_84_0" ] || tar -C "$W" -xzf "$W/boost.tgz"
|
||||
|
||||
# --- bzip2 ---
|
||||
build_dep bzip2 bash -c "
|
||||
cd $W/bzip2-1.0.8 && make -s -j16 CFLAGS='-O2 -fPIC'
|
||||
cp bzlib.h $P/include/ && cp libbz2.a $P/lib/"
|
||||
|
||||
# --- lua 5.2 (library only; the interactive REPL needs readline dev
|
||||
# headers, which we stub — we only link liblua.a into osrm-extract) ---
|
||||
build_dep lua bash -c "
|
||||
mkdir -p $W/local/include/readline $W/local/lib
|
||||
cat > $W/local/include/readline/readline.h <<'HDR'
|
||||
#ifndef READLINE_STUB_H
|
||||
#define READLINE_STUB_H
|
||||
char *readline(const char *prompt);
|
||||
void add_history(const char *line);
|
||||
#endif
|
||||
HDR
|
||||
cat > $W/local/include/readline/history.h <<'HDR'
|
||||
#ifndef HISTORY_STUB_H
|
||||
#define HISTORY_STUB_H
|
||||
void using_history(void);
|
||||
void clear_history(void);
|
||||
#endif
|
||||
HDR
|
||||
ln -sf /usr/lib/x86_64-linux-gnu/libreadline.so.8 $W/local/lib/libreadline.so
|
||||
cd $W/lua-5.2.4/src && make -s clean >/dev/null 2>&1
|
||||
make -s -j16 linux MYCFLAGS='-I$W/local/include' MYLDFLAGS='-L$W/local/lib'
|
||||
cp lua.h luaconf.h lualib.h lauxlib.h lua.hpp $P/include/
|
||||
cp liblua.a $P/lib/"
|
||||
|
||||
# --- nlohmann/json (single header; needed by osmium-tool) ---
|
||||
if [ ! -f "$P/include/nlohmann/json.hpp" ]; then
|
||||
log "nlohmann-json: fetching single header"
|
||||
mkdir -p "$P/include/nlohmann"
|
||||
curl -sL -o "$P/include/nlohmann/json.hpp" \
|
||||
https://github.com/nlohmann/json/releases/download/v3.11.3/json.hpp
|
||||
fi
|
||||
|
||||
# --- oneTBB (CMake, installs TBBConfig.cmake) ---
|
||||
build_dep tbb bash -c "
|
||||
cmake -S $W/oneTBB-2021.13.0 -B $W/tbb-build -DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=$P -DTBB_TEST=OFF -DTBB_STRICT=OFF
|
||||
cmake --build $W/tbb-build -j16
|
||||
cmake --install $W/tbb-build"
|
||||
|
||||
# --- boost: b2 for the libs, then headers + CMake config files ---
|
||||
build_dep boost bash -c "
|
||||
cd $W/boost_1_84_0
|
||||
[ -x ./b2 ] || ./bootstrap.sh
|
||||
./b2 -j16 --with-date_time --with-iostreams --with-program_options \
|
||||
--with-thread --with-test --with-regex \
|
||||
--layout=versioned link=static cxxstd=17
|
||||
rm -rf $P/include/boost && cp -r $W/boost_1_84_0/boost $P/include/boost
|
||||
cp -a $W/boost_1_84_0/stage/lib/libboost_*.a $P/lib/
|
||||
W=$W bash $(dirname "$0")/install-boost-cmake.sh"
|
||||
|
||||
# --- osmium-tool (PBF merging; uses OSRM's vendored libosmium/protozero) ---
|
||||
build_dep osmium bash -c "
|
||||
if [ ! -d $W/osrm-backend-26.4.1 ]; then
|
||||
fetch "https://github.com/Project-OSRM/osrm-backend/archive/refs/tags/v26.4.1.tar.gz" $W/osrm.tar.gz
|
||||
tar -C $W -xzf $W/osrm.tar.gz
|
||||
fi
|
||||
if [ ! -d $W/osmium-tool-1.19.0 ]; then
|
||||
fetch "https://github.com/osmcode/osmium-tool/archive/refs/tags/v1.19.0.tar.gz" $W/osmium.tgz
|
||||
tar -C $W -xzf $W/osmium.tgz
|
||||
fi
|
||||
rm -rf $W/osmium-build
|
||||
cmake -S $W/osmium-tool-1.19.0 -B $W/osmium-build -DCMAKE_BUILD_TYPE=Release \
|
||||
-DOSMIUM_BUILD_PROGRAMS=ON -DOSMIUM_BUILD_TESTS=OFF \
|
||||
-DCMAKE_PREFIX_PATH=$P \
|
||||
-DOSMIUM_INCLUDE_DIR=$W/osrm-backend-26.4.1/third_party/libosmium/include \
|
||||
-DPROTOZERO_INCLUDE_DIR=$W/osrm-backend-26.4.1/third_party/protozero/include
|
||||
cmake --build $W/osmium-build --target osmium -j16"
|
||||
|
||||
log "ALL DEPS DONE"
|
||||
73
router/scripts/install-boost-cmake.sh
Executable file
73
router/scripts/install-boost-cmake.sh
Executable file
|
|
@ -0,0 +1,73 @@
|
|||
#!/usr/bin/env bash
|
||||
# Generate the Boost CMake config files OSRM's find_package(Boost CONFIG)
|
||||
# needs, pointing at a b2-built boost (headers in $P/include/boost,
|
||||
# static libs in $P/lib). Boost release tarballs ship no CMake support,
|
||||
# so we roll minimal configs: one per component + version + main.
|
||||
#
|
||||
# W=/tmp/osm-build bash install-boost-cmake.sh
|
||||
set -euo pipefail
|
||||
W="${W:-/tmp/osm-build}"
|
||||
P="$W/prefix"
|
||||
CM="$P/lib/cmake/Boost-1.84.0"
|
||||
mkdir -p "$CM"
|
||||
|
||||
cat > "$CM/BoostConfigVersion.cmake" <<'EOF'
|
||||
set(PACKAGE_VERSION "1.84.0")
|
||||
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
if(PACKAGE_VERSION VERSION_EQUAL PACKAGE_FIND_VERSION)
|
||||
set(PACKAGE_VERSION_EXACT TRUE)
|
||||
endif()
|
||||
endif()
|
||||
EOF
|
||||
|
||||
# component: cmlist-name b2-lib-name
|
||||
for pair in "date_time date_time" "iostreams iostreams" \
|
||||
"program_options program_options" "thread thread" \
|
||||
"unit_test_framework test" "regex regex" "zlib zlib"; do
|
||||
comp=${pair% *}
|
||||
b2name=${pair#* }
|
||||
cap=$(echo "$comp" | tr 'a-z' 'A-Z')
|
||||
if [ "$comp" = "zlib" ]; then
|
||||
# OSRM lists Boost_ZLIB_LIBRARY in BOOST_ENGINE_LIBRARIES; use system zlib
|
||||
cat > "$CM/Boost${cap}Config.cmake" <<EOF
|
||||
set(Boost_${cap}_LIBRARY /usr/lib/x86_64-linux-gnu/libz.so)
|
||||
set(Boost_${cap}_FOUND TRUE)
|
||||
set(Boost_${comp}_FOUND TRUE)
|
||||
EOF
|
||||
continue
|
||||
fi
|
||||
lib=$(ls "$P"/lib/libboost_${b2name}*.a 2>/dev/null | head -1 || true)
|
||||
if [ -z "$lib" ]; then
|
||||
echo "FATAL: no static lib for $comp (b2name $b2name)" >&2
|
||||
exit 1
|
||||
fi
|
||||
cat > "$CM/Boost${cap}Config.cmake" <<EOF
|
||||
set(Boost_${cap}_LIBRARY "$lib")
|
||||
set(Boost_${cap}_FOUND TRUE)
|
||||
set(Boost_${comp}_FOUND TRUE)
|
||||
EOF
|
||||
done
|
||||
|
||||
cat > "$CM/BoostConfig.cmake" <<EOF
|
||||
if(Boost_FOUND)
|
||||
return()
|
||||
endif()
|
||||
set(Boost_VERSION 108400)
|
||||
set(Boost_VERSION_STRING "1.84.0")
|
||||
set(Boost_LIB_VERSION "1_84")
|
||||
get_filename_component(Boost_INCLUDE_DIRS "$P/include" ABSOLUTE)
|
||||
set(Boost_INCLUDE_DIR "\${Boost_INCLUDE_DIRS}")
|
||||
set(Boost_LIBRARIES "")
|
||||
foreach(_comp \${Boost_FIND_COMPONENTS})
|
||||
string(TOUPPER "\${_comp}" _uc)
|
||||
include("\${CMAKE_CURRENT_LIST_DIR}/Boost\${_uc}Config.cmake")
|
||||
list(APPEND Boost_LIBRARIES \${Boost_\${_uc}_LIBRARY})
|
||||
endforeach()
|
||||
set(Boost_FOUND TRUE)
|
||||
EOF
|
||||
|
||||
ls "$CM"
|
||||
echo "boost cmake config installed in $CM"
|
||||
104
router/scripts/setup-osrm.sh
Normal file → Executable file
104
router/scripts/setup-osrm.sh
Normal file → Executable file
|
|
@ -1,68 +1,90 @@
|
|||
#!/usr/bin/env bash
|
||||
# Self-host the OSRM router over the NH+MA+CT+NY extract.
|
||||
# Prereqs: cmake, g++, make, >=12GB RAM for extract, >=10GB disk.
|
||||
# Build + run the self-hosted OSRM router over the NH+MA+CT+NY extract.
|
||||
#
|
||||
# The PBFs are pre-downloaded in ../osm/ (us-new-hampshire, us-connecticut,
|
||||
# us-massachusetts, us-new-york .osm.pbf, from the geofabrik mirror on
|
||||
# HuggingFace: NoeFlandre/osm-geofabrik-raw-pbf-extracts).
|
||||
# Steps: deps.sh (bzip2/lua/tbb/boost/osmium, no sudo) → build OSRM 26.4.1
|
||||
# → merge the 4 state PBFs → extract → partition → customize → serve :5000.
|
||||
#
|
||||
# Artifacts go to ../osm/build/. Router ends up on http://localhost:5000.
|
||||
# Usage: scripts/setup-osrm.sh # everything, then 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
|
||||
# durable dir (and the extract's ~8 GB lives under $W/data).
|
||||
#
|
||||
# PBFs are pre-downloaded in ../../osm/ (see router/README.md); ~1.1 GB.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
OSM_DIR="$(pwd)/osm"
|
||||
BUILD_DIR="$OSM_DIR/build"
|
||||
DATA_DIR="$BUILD_DIR/data"
|
||||
OSRM_BIN="$BUILD_DIR/osrm-backend-26.4.1/build"
|
||||
W="${W:-/tmp/osm-build}"
|
||||
P="$W/prefix"
|
||||
OSM_DIR="$(cd ../.. && pwd)/osm"
|
||||
DATA_DIR="${DATA_DIR:-$W/data}"
|
||||
OSRM_SRC="$W/osrm-backend-26.4.1"
|
||||
OSRM_BIN="$W/build"
|
||||
SERVE=1
|
||||
[ "${1:-}" = "--no-serve" ] && SERVE=0
|
||||
mkdir -p "$DATA_DIR"
|
||||
|
||||
step() { echo; echo "=== $1"; }
|
||||
|
||||
step "1/5 OSRM binaries"
|
||||
step "1/6 dependencies (bzip2, lua, tbb, boost, osmium)"
|
||||
bash deps.sh
|
||||
|
||||
step "2/6 OSRM 26.4.1"
|
||||
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
|
||||
tar -C "$W" -xzf "$W/osrm.tar.gz"
|
||||
fi
|
||||
if [ ! -x "$OSRM_BIN/osrm-extract" ]; then
|
||||
if [ ! -d "$BUILD_DIR/osrm-backend-26.4.1" ]; then
|
||||
curl -sL -o "$BUILD_DIR/osrm.tar.gz" https://github.com/Project-OSRM/osrm-backend/archive/refs/tags/v26.4.1.tar.gz
|
||||
tar -C "$BUILD_DIR" -xzf "$BUILD_DIR/osrm.tar.gz"
|
||||
fi
|
||||
# Boost is header-usage only for OSRM; point BOOST_ROOT at a source tree.
|
||||
if [ ! -d "$BUILD_DIR/boost_1_84_0" ]; then
|
||||
curl -sL -o "$BUILD_DIR/boost.tgz" https://archives.boost.io/release/1.84.0/source/boost_1_84_0.tar.gz
|
||||
tar -C "$BUILD_DIR" -xzf "$BUILD_DIR/boost.tgz"
|
||||
fi
|
||||
cmake -S "$BUILD_DIR/osrm-backend-26.4.1" -B "$OSRM_BIN" \
|
||||
-DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=OFF -DWITH_EXAMPLES=OFF \
|
||||
-DBOOST_ROOT="$BUILD_DIR/boost_1_84_0"
|
||||
# -Wno-maybe-uninitialized: GCC 12 + boost 1.84 spirit X3 false positive
|
||||
# under OSRM's -Werror.
|
||||
cmake -S "$OSRM_SRC" -B "$OSRM_BIN" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH="$P" \
|
||||
-DCMAKE_CXX_FLAGS="-Wno-maybe-uninitialized"
|
||||
cmake --build "$OSRM_BIN" -j"$(nproc)"
|
||||
fi
|
||||
ls -la "$OSRM_BIN"/osrm-extract "$OSRM_BIN"/osrm-routed
|
||||
|
||||
step "2/5 OSM PBFs"
|
||||
step "3/6 OSM PBFs (NH+MA+CT+NY)"
|
||||
if [ ! -s "$OSM_DIR/us-new-hampshire.osm.pbf" ]; then
|
||||
echo "PBFs missing; downloading from the geofabrik HF mirror (~1.1 GB)..."
|
||||
for f in us-new-hampshire us-connecticut us-massachusetts us-new-york; do
|
||||
if [ ! -s "$OSM_DIR/$f.osm.pbf" ]; then
|
||||
curl -sL -o "$OSM_DIR/$f.osm.pbf" \
|
||||
[ -s "$OSM_DIR/$f.osm.pbf" ] || curl -sL -o "$OSM_DIR/$f.osm.pbf" \
|
||||
"https://huggingface.co/datasets/NoeFlandre/osm-geofabrik-raw-pbf-extracts/resolve/main/$f-latest.osm.pbf"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
ls -la "$OSM_DIR"/us-*.osm.pbf
|
||||
|
||||
step "3/5 extract (needs ~12GB RAM; this is the slow part)"
|
||||
touch "$DATA_DIR/timestamp"
|
||||
if [ ! -s "$DATA_DIR/northeast.osrm" ] || [ ! -s "$DATA_DIR/northeast.osrm.tile" ]; then
|
||||
"$OSRM_BIN/osrm-extract" \
|
||||
step "4/6 merge PBFs (osrm-extract takes one input file)"
|
||||
MERGED="$DATA_DIR/northeast.osm.pbf"
|
||||
if [ ! -s "$MERGED" ]; then
|
||||
"$W/osmium-build/osmium" merge \
|
||||
"$OSM_DIR/us-new-hampshire.osm.pbf" \
|
||||
"$OSM_DIR/us-connecticut.osm.pbf" \
|
||||
"$OSM_DIR/us-massachusetts.osm.pbf" \
|
||||
"$OSM_DIR/us-new-york.osm.pbf" \
|
||||
--profile-file "$OSRM_BIN/../profiles/driving.lua" \
|
||||
--timestamp-file "$DATA_DIR/timestamp" \
|
||||
--output-location "$DATA_DIR/northeast" \
|
||||
--ignore-waterway --ignore-tunnels 2>&1 | tail -5
|
||||
-o "$MERGED"
|
||||
fi
|
||||
ls -la "$MERGED"
|
||||
|
||||
step "5/6 extract + partition + customize (extract needs ~9-12GB RAM)"
|
||||
if [ ! -s "$DATA_DIR/northeast.osrm.ebg" ]; then
|
||||
"$OSRM_BIN/osrm-extract" "$MERGED" \
|
||||
-p "$OSRM_SRC/profiles/car.lua" \
|
||||
-o "$DATA_DIR/northeast"
|
||||
fi
|
||||
if [ ! -s "$DATA_DIR/northeast.osrm.partition" ]; then
|
||||
"$OSRM_BIN/osrm-partition" "$DATA_DIR/northeast"
|
||||
fi
|
||||
if [ ! -s "$DATA_DIR/northeast.osrm.tld" ]; then
|
||||
# v26 bakes the profile into the extract; customize takes no -p.
|
||||
"$OSRM_BIN/osrm-customize" "$DATA_DIR/northeast"
|
||||
fi
|
||||
|
||||
step "4/5 partition + customize"
|
||||
"$OSRM_BIN/osrm-partition" --input-location "$DATA_DIR/northeast"
|
||||
"$OSRM_BIN/osrm-customize" --input-location "$DATA_DIR/northeast" --profile-file "$OSRM_BIN/../profiles/driving.lua"
|
||||
if [ "$SERVE" = 0 ]; then
|
||||
echo "done (not serving; start with: $OSRM_BIN/osrm-routed --algorithm mld --port 5000 $DATA_DIR/northeast.osrm)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
step "5/5 serve"
|
||||
echo "Starting osrm-routed on :5000 (Ctrl-C to stop)"
|
||||
step "6/6 serve on :5000 (Ctrl-C to stop)"
|
||||
exec "$OSRM_BIN/osrm-routed" --algorithm mld --port 5000 "$DATA_DIR/northeast.osrm"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user