feat: bias getFeature to lastId
Some checks failed
TrafficCue CI / check (push) Failing after 1m36s

This commit is contained in:
2025-10-22 20:40:24 +02:00
parent 787b3b108b
commit 640a2e8ef6
3 changed files with 46 additions and 14 deletions

View File

@ -1,7 +1,7 @@
import { LNV_SERVER } from "$lib/services/hosts";
import { routing } from "$lib/services/navigation/routing.svelte";
import type { WrappedValue } from "$lib/services/stores.svelte";
import { getFeature, getMeta } from "$lib/services/TileMeta";
import { getFeature } from "$lib/services/TileMeta";
import { lineString, nearestPointOnLine, point } from "@turf/turf";
import { map } from "./map.svelte";
@ -51,6 +51,7 @@ const roadFeature: WrappedValue<GeoJSON.Feature | null> = $state({
const snappedLocation: WrappedValue<WorldLocation | null> = $state({
current: null,
});
let lastFeatureId: string | null = null;
export function getRoadMetadata() {
return roadMetadata;
@ -116,15 +117,19 @@ export function watchLocation() {
getFeature(
{ lat: location.lat, lon: location.lng },
"transportation",
(f) => {
if(f.properties) {
return !blacklist.includes(f.properties["class"]);
}
return true;
{
filter: (f) => {
if(f.properties) {
return !blacklist.includes(f.properties["class"]);
}
return true;
},
lastId: lastFeatureId || undefined,
}
).then((feature) => {
roadFeature.current = feature;
roadMetadata.current = feature ? feature.properties : null;
lastFeatureId = feature ? String(feature.id) : null;
snapLocation();
});

View File

@ -3,15 +3,16 @@ import { FSSource, hasPMTiles } from "./OfflineTiles";
import { PMTiles } from "pmtiles";
import { VectorTile } from "@mapbox/vector-tile";
import Protobuf from "pbf";
import { location } from "$lib/components/lnv/location.svelte";
function getFeatureDistance(f: GeoJSON.Feature, point: [number, number]) {
if (f.geometry.type === "LineString") {
return pointToLineDistance(point, lineString(f.geometry.coordinates));
return pointToLineDistance(point, lineString(f.geometry.coordinates), { units: "meters" });
} else if (f.geometry.type === "MultiLineString") {
// Compute the min distance across all parts
return Math.min(
...f.geometry.coordinates.map((coords) =>
pointToLineDistance(point, lineString(coords)),
pointToLineDistance(point, lineString(coords), { units: "meters" }),
),
);
} else {
@ -19,7 +20,17 @@ function getFeatureDistance(f: GeoJSON.Feature, point: [number, number]) {
}
}
export async function getFeature(coord: WorldLocation, layer: string, filter?: (feature: GeoJSON.Feature) => boolean) {
interface GetFeatureOptions {
lastId?: string;
filter?: (feature: GeoJSON.Feature) => boolean;
}
function getBias() {
if(!location.speed) return 5;
return Math.max(5, Math.min(15, location.speed * 0.5)); // Bias increases with speed, min 5, max 15, 0.5 per km/h
}
export async function getFeature(coord: WorldLocation, layer: string, { lastId, filter }: GetFeatureOptions = {}) {
const zxy = coordToTile(coord, 14);
const tile = await fetchTile(zxy.z, zxy.x, zxy.y);
const layerData = tile.layers[layer];
@ -36,15 +47,31 @@ export async function getFeature(coord: WorldLocation, layer: string, filter?: (
).filter((f) => (filter ? filter(f) : true));
if (filtered.length === 0) return null;
const nearest = filtered.reduce((a, b) => {
const distA = getFeatureDistance(a, [coord.lon, coord.lat]);
const distB = getFeatureDistance(b, [coord.lon, coord.lat]);
let distA = getFeatureDistance(a, [coord.lon, coord.lat]);
let distB = getFeatureDistance(b, [coord.lon, coord.lat]);
console.log("lastId:", lastId, "a.id:", a.id, "b.id:", b.id);
const STAY_BIAS = getBias();
if (lastId && String(a.id) == lastId) {
console.log("Applying stay bias to B");
distB += STAY_BIAS;
}
if (lastId && String(b.id) == lastId) {
console.log("Applying stay bias to A");
distA += STAY_BIAS;
}
console.log("Distances:", distA, distB);
return distA < distB ? a : b;
});
console.log("ID: ", nearest.id);
return nearest;
}
export async function getMeta(coord: WorldLocation, layer: string, filter?: (feature: GeoJSON.Feature) => boolean) {
const nearest = await getFeature(coord, layer, filter);
export async function getMeta(coord: WorldLocation, layer: string, options?: GetFeatureOptions) {
const nearest = await getFeature(coord, layer, options);
return nearest ? nearest.properties : null;
}

View File

@ -9,4 +9,4 @@ export const LNV_SERVER =
? "http://localhost:3000/api"
: location.hostname.includes("staging")
? "https://staging-trafficcue-api.picoscratch.de/api"
: "https://trafficcue-api.picoscratch.de/api";
: "https://staging-trafficcue-api.picoscratch.de/api";