Files
wanderer/web/src/lib/stores/valhalla_store.ts
2025-01-11 22:43:32 +01:00

90 lines
3.3 KiB
TypeScript

import GPX from "$lib/models/gpx/gpx";
import type Track from "$lib/models/gpx/track";
import TrackSegment from "$lib/models/gpx/track-segment";
import Waypoint from "$lib/models/gpx/waypoint";
import { type ValhallaAnchor, type ValhallaHeightResponse, type ValhallaRouteResponse } from "$lib/models/valhalla";
import { APIError } from "$lib/util/api_util";
import { decodePolyline, encodePolyline } from "$lib/util/polyline_util";
const emtpyTrack: Track = { trkseg: [] }
export let route: GPX = new GPX({ trk: [emtpyTrack] });
export let anchors: ValhallaAnchor[] = [];
export function clearRoute() {
route = new GPX({ trk: [emtpyTrack] });
anchors = [];
}
export function setRoute(newRoute: GPX) {
route = newRoute
}
export async function calculateRouteBetween(startLat: number, startLon: number, endLat: number, endLon: number, costing: string = "pedestrian", autoRoute: boolean = true) {
let shape;
if (autoRoute) {
let costingBody;
switch (costing) {
case "bicycle":
costingBody = { "costing": "bicycle", "costing_options": { "bicycle": { "bicycle_type": "Hybrid", "use_roads": 0.5, "use_hills": 0.5, "avoid_bad_surfaces": 0.5, "use_ferry": 0 } } }
break;
case "auto":
costingBody = { "costing": "auto", "costing_options": { "auto": { "use_ferry": 0 } } }
default:
costingBody = { "costing": costing, "costing_options": { costing: { "max_hiking_difficulty": 6, "use_ferry": 0 } } }
break;
}
const requestBody = {
"directions_type": "none",
"locations": [{ "lat": startLat, "lon": startLon }, { "lat": endLat, "lon": endLon }],
...costingBody
}
let r = await fetch("/api/v1/valhalla/route", { method: "POST", body: JSON.stringify(requestBody) })
if (!r.ok) {
const response = await r.json();
throw new APIError(r.status, response.message, response.detail)
}
const routeResponse: ValhallaRouteResponse = await r.json();
shape = routeResponse.trip.legs[0].shape
} else {
shape = encodePolyline([[startLat, startLon], [endLat, endLon]])
}
const r2 = await fetch("/api/v1/valhalla/height", { method: "POST", body: JSON.stringify({ encoded_polyline: shape }) })
if (!r2.ok) {
const response = await r2.json();
throw new APIError(r2.status, response.message, response.detail)
}
const heightResponse: ValhallaHeightResponse = await r2.json()
const points = decodePolyline(shape);
const waypoints = points.map((p, i) => new Waypoint({ $: { lat: p[0], lon: p[1] }, ele: heightResponse.height[i] }))
return waypoints
}
export async function insertIntoRoute(waypoints: Waypoint[], index?: number) {
const segment = new TrackSegment({ trkpt: waypoints })
if (index) {
route.trk?.at(0)?.trkseg?.splice(index, 0, segment);
} else {
route.trk?.at(0)?.trkseg?.push(segment);
}
}
export async function editRoute(index: number, waypoints: Waypoint[]) {
const segment = route.trk?.at(0)?.trkseg?.at(index)
if (segment) {
segment.trkpt = waypoints
}
}
export function deleteFromRoute(index: number) {
route.trk?.at(0)?.trkseg?.splice(index, 1);
}