refactor(map): build OSRM leg connectors in one place

calculateSegments and the cached legs call turned each OSRM leg into the
same connector record line by line. That record now comes from
osrmLegSegment; the legs call keeps adding its durationText on top, so
both answers stay exactly as they were.
This commit is contained in:
Maurice
2026-10-09 14:38:29 +02:00
parent feef872776
commit 369697650f
2 changed files with 54 additions and 29 deletions
@@ -17,6 +17,7 @@ import {
routeEngineFor,
sameRoad,
furthestFrom,
osrmLegSegment,
} from './RouteCalculator'
// Every route now goes to the FOSSGIS per-profile hosts. The car-only project-osrm.org
@@ -1246,3 +1247,28 @@ describe('a trip that avoids something', () => {
expect(routes[1]).toMatchObject({ avoids: 'motorway', engine: 'valhalla', hasFerry: true })
})
})
describe('osrmLegSegment', () => {
const waypoints = [{ lat: 48, lng: 2 }, { lat: 50, lng: 4 }, { lat: 52, lng: 6 }]
it('spans waypoint i to i + 1 with the label at the midpoint', () => {
const seg = osrmLegSegment({ distance: 1500, duration: 600 }, 1, waypoints)
expect(seg.from).toEqual([50, 4])
expect(seg.to).toEqual([52, 6])
expect(seg.mid).toEqual([51, 5])
expect(seg.distance).toBe(1500)
expect(seg.duration).toBe(600)
})
it('formats driving as measured and walking at 5 km/h', () => {
const seg = osrmLegSegment({ distance: 5000, duration: 600 }, 0, waypoints)
expect(seg.drivingText).toBe('10 min')
expect(seg.walkingText).toBe('1 h 0 min')
expect(seg.durationText).toBeUndefined()
})
it('writes short metric distances in metres', () => {
useSettingsStore.setState({ settings: { ...useSettingsStore.getState().settings, distance_unit: 'metric' } })
expect(osrmLegSegment({ distance: 420.4, duration: 60 }, 0, waypoints).distanceText).toBe('420 m')
})
})
+28 -29
View File
@@ -470,20 +470,29 @@ export async function calculateSegments(
if (data.code !== 'Ok' || !data.routes?.[0]) throw new Error('No route found')
const legs = data.routes[0].legs
return legs.map((leg: { distance: number; duration: number }, i: number): RouteSegment => {
const from: [number, number] = [waypoints[i].lat, waypoints[i].lng]
const to: [number, number] = [waypoints[i + 1].lat, waypoints[i + 1].lng]
const mid: [number, number] = [(from[0] + to[0]) / 2, (from[1] + to[1]) / 2]
const walkingDuration = leg.distance / (5000 / 3600)
return {
mid, from, to,
distance: leg.distance,
duration: leg.duration,
walkingText: formatDuration(walkingDuration),
drivingText: formatDuration(leg.duration),
distanceText: formatRouteDistance(leg.distance),
}
})
return legs.map((leg: OsrmLeg, i: number): RouteSegment => osrmLegSegment(leg, i, waypoints))
}
interface OsrmLeg { distance: number; duration: number }
/**
* The connector data for OSRM leg i, which runs from waypoint i to waypoint i + 1:
* both ends, the midpoint the label sits on, and the walking time at 5 km/h next to
* the driving time OSRM measured.
*/
export function osrmLegSegment(leg: OsrmLeg, i: number, waypoints: Waypoint[]): RouteSegment {
const from: [number, number] = [waypoints[i].lat, waypoints[i].lng]
const to: [number, number] = [waypoints[i + 1].lat, waypoints[i + 1].lng]
const mid: [number, number] = [(from[0] + to[0]) / 2, (from[1] + to[1]) / 2]
const walkingDuration = leg.distance / (5000 / 3600)
return {
mid, from, to,
distance: leg.distance,
duration: leg.duration,
walkingText: formatDuration(walkingDuration),
drivingText: formatDuration(leg.duration),
distanceText: formatRouteDistance(leg.distance),
}
}
/**
@@ -617,22 +626,12 @@ async function osrmWithLegs(
const coordinates: [number, number][] = route.geometry.coordinates.map(
([lng, lat]: [number, number]) => [lat, lng]
)
// The day plan's connectors also show the leg's own duration line.
const legs: RouteSegment[] = (route.legs || []).map(
(leg: { distance: number; duration: number }, i: number): RouteSegment => {
const from: [number, number] = [waypoints[i].lat, waypoints[i].lng]
const to: [number, number] = [waypoints[i + 1].lat, waypoints[i + 1].lng]
const mid: [number, number] = [(from[0] + to[0]) / 2, (from[1] + to[1]) / 2]
const walkingDuration = leg.distance / (5000 / 3600)
return {
mid, from, to,
distance: leg.distance,
duration: leg.duration,
walkingText: formatDuration(walkingDuration),
drivingText: formatDuration(leg.duration),
distanceText: formatRouteDistance(leg.distance),
durationText: formatDuration(leg.duration),
}
}
(leg: OsrmLeg, i: number): RouteSegment => ({
...osrmLegSegment(leg, i, waypoints),
durationText: formatDuration(leg.duration),
})
)
const snapped = readSnapped(data, waypoints)