feat: add experimental landmark-based voice guidance
This commit is contained in:
83
src/lib/services/navigation/VoiceGuidance.ts
Normal file
83
src/lib/services/navigation/VoiceGuidance.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import { OVERPASS_SERVER } from "../hosts";
|
||||||
|
import type { OverpassResult } from "../Overpass";
|
||||||
|
|
||||||
|
export async function generateVoiceGuidance(maneuver: Maneuver, shape: WorldLocation[]): Promise<string> {
|
||||||
|
const landmarks = await findNearbyLandmarks(shape[maneuver.begin_shape_index]);
|
||||||
|
if(landmarks.length == 0) {
|
||||||
|
return maneuver.verbal_pre_transition_instruction;
|
||||||
|
}
|
||||||
|
console.log("Original instruction:", maneuver.verbal_pre_transition_instruction);
|
||||||
|
return `Hinter ${landmarks[0].tags.name}, ${typeToName(maneuver.type)} auf ${(maneuver.street_names || []).join(", ")}.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function typeToName(type: number) {
|
||||||
|
switch (type) {
|
||||||
|
case 4:
|
||||||
|
return "Ziel erreicht";
|
||||||
|
case 5:
|
||||||
|
return "Ziel auf der rechten Seite erreicht";
|
||||||
|
case 6:
|
||||||
|
return "Ziel auf der linken Seite erreicht";
|
||||||
|
case 8:
|
||||||
|
return "Weiterfahren";
|
||||||
|
case 9:
|
||||||
|
return "Leicht rechts abbiegen";
|
||||||
|
case 10:
|
||||||
|
return "Rechts abbiegen";
|
||||||
|
case 11:
|
||||||
|
return "Scharf rechts abbiegen";
|
||||||
|
case 12:
|
||||||
|
case 13:
|
||||||
|
return "Umdrehen";
|
||||||
|
case 14:
|
||||||
|
return "Scharf links abbiegen";
|
||||||
|
case 15:
|
||||||
|
return "Links abbiegen";
|
||||||
|
case 16:
|
||||||
|
return "Leicht links abbiegen";
|
||||||
|
case 20:
|
||||||
|
return "Rechts abfahren";
|
||||||
|
case 21:
|
||||||
|
return "Links abfahren";
|
||||||
|
case 22:
|
||||||
|
return "Geradeaus weiterfahren";
|
||||||
|
case 23:
|
||||||
|
return "Rechts halten";
|
||||||
|
case 24:
|
||||||
|
return "Links halten";
|
||||||
|
case 25:
|
||||||
|
return "Einordnen";
|
||||||
|
case 26:
|
||||||
|
case 27:
|
||||||
|
return "Kreisverkehr";
|
||||||
|
case 37:
|
||||||
|
return "Rechts einordnen";
|
||||||
|
case 38:
|
||||||
|
return "Links einordnen";
|
||||||
|
default:
|
||||||
|
return "Unbekannt";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function findNearbyLandmarks(location: WorldLocation) {
|
||||||
|
const radius = 100;
|
||||||
|
const lat = location.lat;
|
||||||
|
const lon = location.lon;
|
||||||
|
const res = await fetch(OVERPASS_SERVER, {
|
||||||
|
method: "POST",
|
||||||
|
body: `[out:json];
|
||||||
|
(
|
||||||
|
node(around:${radius}, ${lat}, ${lon})["tourism"="artwork"]["name"];
|
||||||
|
way(around:${radius}, ${lat}, ${lon})["tourism"="artwork"]["name"];
|
||||||
|
node(around:${radius}, ${lat}, ${lon})["shop"]["name"];
|
||||||
|
way(around:${radius}, ${lat}, ${lon})["shop"]["name"];
|
||||||
|
);
|
||||||
|
out center tags;`,
|
||||||
|
}).then((res) => res.json() as Promise<OverpassResult>);
|
||||||
|
// Sort by distance to the location
|
||||||
|
return res.elements.sort((a, b) => {
|
||||||
|
const distA = Math.sqrt(Math.pow(a.lat! - lat, 2) + Math.pow(a.lon! - lon, 2));
|
||||||
|
const distB = Math.sqrt(Math.pow(b.lat! - lat, 2) + Math.pow(b.lon! - lon, 2));
|
||||||
|
return distA - distB;
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@ import { map } from "$lib/components/lnv/map.svelte";
|
|||||||
import say from "./TTS";
|
import say from "./TTS";
|
||||||
import type { ValhallaRequest } from "./ValhallaRequest";
|
import type { ValhallaRequest } from "./ValhallaRequest";
|
||||||
import type { LngLatBoundsLike } from "maplibre-gl";
|
import type { LngLatBoundsLike } from "maplibre-gl";
|
||||||
|
import { generateVoiceGuidance } from "./VoiceGuidance";
|
||||||
|
|
||||||
export const routing = $state({
|
export const routing = $state({
|
||||||
geojson: {
|
geojson: {
|
||||||
@ -192,11 +193,13 @@ async function tickRoute() {
|
|||||||
);
|
);
|
||||||
if (distanceToEnd <= verbalDistance) {
|
if (distanceToEnd <= verbalDistance) {
|
||||||
hasAnnouncedPreInstruction = true;
|
hasAnnouncedPreInstruction = true;
|
||||||
|
const instruction = await generateVoiceGuidance(currentManeuver, polyline);
|
||||||
console.log(
|
console.log(
|
||||||
"[Verbal instruction] ",
|
"[Verbal instruction] ",
|
||||||
currentManeuver.verbal_pre_transition_instruction,
|
// currentManeuver.verbal_pre_transition_instruction,
|
||||||
|
instruction
|
||||||
);
|
);
|
||||||
say(currentManeuver.verbal_pre_transition_instruction);
|
say(instruction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user